1.什么是Vue? Vue.js 是一套构建用户界面的框架,它不仅易于上手,还可以与其它第三方库整合(Swiper、IScroll、…)。
2.框架和库的区别? 框架:是一套完整的解决方案;对项目的侵入性较大,项目如果需要更换框架,则需要重构整个项目。 库(插件):提供某一个小功能,对项目的侵入性较小,如果某个库无法完成某些需求,可以很容易切换到其它库实现需求。 例如: 从jQuery 切换到 Zepto, 无缝切换 从IScroll切换到ScrollMagic, 只需要将用到IScroll的代码替换成ScrollMagic代码即可
3.为什么要学习框架? 提升开发效率:在企业中,时间就是效率,效率就是金钱; 前端提高开发效率的发展历程:原生JS -> jQuery之类的类库 -> 前端模板引擎 -> Vue / React / Angular
4.框架有很多, 为什么要先学Vue Vue、Angular、React一起,被称之为前端三大主流框架! 但是Angular、React是老外编写的, 所以所有的资料都是英文的 而Vue是国人编写的, 所以所有的资料都是中文的, 并且Vue中整合了Angular、React中的众多优点 所以为了降低我们的学习难度, 我们先学Vue, 学完之后再学习Angular和React
5.使用Vue有哪些优势? 5.1Vue的核心概念之一: 通过数据驱动界面更新, 无需操作DOM来更新界面 使用Vue我们只需要关心如何获取数据, 如何处理数据, 如何编写业务逻辑代码, 我们只需要将处理好的数据交给Vue, Vue就会自动将数据渲染到模板中(界面上) 5.2Vue的核心概念之二: 组件化开发,我们可以将网页拆分成一个个独立的组件来编写 将来再通过封装好的组件拼接成一个完整的网页 https://cn.vuejs.org/images/components.png
v-model.trim 去除前后空格 v-model.number 将输入的值转换为数字 v-model.lazy
1.什么是v-text指令 v-text就相当于过去学习的innerText
2.什么是v-html指令 v-html就相当于过去学习的innerHTML
<div id="app"> <!--插值的方式: 可以将指定的数据插入到指定的位置--> <p>++++{{ name }}++++</p> <!--插值的方式: 不会解析HTML--> <p>++++{{ msg }}++++</p> <!--v-text的方式: 会覆盖原有的内容--> <p v-text="name">++++++++</p> <!--v-text的方式: 也不会解析HTML--> <p v-text="msg">++++++++</p> <!--v-html的方式: 会覆盖原有的内容--> <p v-html="name">++++++++</p> <!--v-html的方式:会解析HTML--> <p v-html="msg">++++++++</p> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { name: "Andy", msg: "<span>我是span</span>" } }); </script>1.v-for注意点 1.1v-for为了提升性能, 在更新已渲染过的元素列表时,会采用“就地复用”策略。 也正是因为这个策略, 在某些时刻会导致我们的数据混乱 例如: 在列表前面新增了内容 1.2为了解决这个问题, 我们可以在渲染列表的时候给每一个元素加上一个独一无二的key v-for在更新已经渲染过的元素列表时, 会先判断key是否相同, 如果相同则复用, 如果不同则重新创建
2.key属性注意点 不能使用index的作为key,因为当列表的内容新增或者删除时index都会发生变化
<!--这里就是MVVM中的View--> <div id="app"> <form> <input type="text" v-model="name"> <input type="submit" value="添加" @click.prevent="add"> </form> <ul> <!-- <li v-for="(person,index) in persons" :key="person.id">--> <li v-for="(person,index) in persons" :key="index"> <input type="checkbox"> <span>{{index}} --- {{person.name}}</span> </li> </ul> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { persons: [ {name: "zs", id: 1}, {name: "ls", id: 2}, {name: "ww", id: 3} ], name: "" }, // 专门用于存储监听事件回调函数 methods: { add(){ let lastPerson = this.persons[this.persons.length - 1]; let newPerson = {name: this.name, id: lastPerson.id + 1}; // this.persons.push(newPerson); this.persons.unshift(newPerson); this.name = ""; } }, // 专门用于定义计算属性的 computed: { } }); </script>1.自定义全局指令 在Vue中除了可以使用Vue内置的一些指令以外, 我们还可以自定义指令
2.自定义全局指令语法 ue.directive(‘自定义指令名称’, { 生命周期名称: function (el) { 指令业务逻辑代码 } });
3.指令生命周期方法 自定义指令时一定要明确指令的业务逻辑代码更适合在哪个阶段执行 例如: 指令业务逻辑代码中没有用到元素事件, 那么可以在bind阶段执行 例如: 指令业务逻辑代码中用到了元素事件, 那么就需要在inserted阶段执行
4.自定义指令注意点 使用时需要加上v-, 而在自定义时不需要加上v-
<!--这里就是MVVM中的View--> <div id="app"> <!-- <p v-color>我是段落</p>--> <input type="text" v-focus> </div> <script> /* directive方法接收两个参数 第一个参数: 指令的名称 第二个参数: 对象 注意点: 在自定义指令的时候, 在指定指令名称的时候, 不需要写v- 注意点: 指令可以在不同的生命周期阶段执行 bind: 指令被绑定到元素上的时候执行 inserted: 绑定指令的元素被添加到父元素上的时候执行 * */ Vue.directive("color", { // 这里的el就是被绑定指令的那个元素 bind: function (el) { el.style.color = "red"; } }); Vue.directive("focus", { // 这里的el就是被绑定指令的那个元素 inserted: function (el) { el.focus(); } }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { } }); </script>1.自定义指令参数 在使用官方指令的时候我们可以给指令传参 例如: v-model=“name” 在我们自定义的指令中我们也可以传递传递
2.获取自定义指令传递的参数 在执行自定义指令对应的方法的时候, 除了会传递el给我们, 还会传递一个对象给我们 这个对象中就保存了指令传递过来的参数
<!--这里就是MVVM中的View--> <div id="app"> <!-- <p v-color="'blue'">我是段落</p>--> <p v-color="curColor">我是段落</p> </div> <script> Vue.directive("color", { // 这里的el就是被绑定指令的那个元素 bind: function (el, obj) { // el.style.color = "red"; el.style.color = obj.value; } }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { curColor: 'green' }, // 专门用于存储监听事件回调函数 methods: { } }); </script>1.自定义全局指令的特点 在任何一个Vue实例控制的区域中都可以使用
2.自定义局部指令的特点 只能在自定义的那个Vue实例中使用
3.如何自定义一个局部指令 给创建Vue实例时传递的对象添加
directives: { // key: 指令名称 // value: 对象 'color': { bind: function (el, obj) { el.style.color = obj.value; } } } <!--这里就是MVVM中的View--> <div id="app1"> <p v-color="'blue'">我是段落</p> </div> <div id="app2"> <p v-color="'red'">我是段落</p> </div> <script> /* Vue.directive("color", { // 这里的el就是被绑定指令的那个元素 bind: function (el, obj) { el.style.color = obj.value; } }); */ // 这里就是MVVM中的View Model let vue1 = new Vue({ el: '#app1', // 这里就是MVVM中的Model data: {}, // 专门用于存储监听事件回调函数 methods: {} }); // 这里就是MVVM中的View Model let vue2 = new Vue({ el: '#app2', // 这里就是MVVM中的Model data: {}, // 专门用于存储监听事件回调函数 methods: {}, // 专门用于定义局部指令的 directives: { "color": { // 这里的el就是被绑定指令的那个元素 bind: function (el, obj) { el.style.color = obj.value; } } } }); </script>1.插值语法特点 可以在{{}}中编写合法的JavaScript表达式
2.在插值语法中编写JavaScript表达式缺点 2.1没有代码提示 2.2语句过于复杂不利于我们维护
3.如何解决? 对于任何复杂逻辑,你都应当使用计算属性
<!--这里就是MVVM中的View--> <div id="app"> <p>{{name}}</p> <p>{{age + 1}}</p> <p>{{msg.split("").reverse().join("")}}</p> 注意点: 虽然在定义计算属性的时候是通过一个函数返回的数据 但是在使用计算属性的时候不能在计算属性名称后面加上() 因为它是一个属性不是一个函数(方法) <p>{{msg2}}</p> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { name: "lnj", age: 18, msg: "abcdef" }, // 专门用于存储监听事件回调函数 methods: {}, // 专门用于定义计算属性的 computed: { msg2: function () { let res = "abcdef".split("").reverse().join(""); return res; } } }); </script>1.计算属性和函数 通过计算属性我们能拿到处理后的数据, 但是通过函数我们也能拿到处理后的数据 那么计算属性和函数有什么区别呢? 2.1函数"不会"将计算的结果缓存起来, 每一次访问都会重新求值 2.2计算属性"会"将计算的结果缓存起来, 只要数据没有发生变化, 就不会重新求值
2.计算属性应用场景 计算属性:比较适合用于计算不会频繁发生变化的的数据
1.什么是过滤器? 过滤器和函数和计算属性一样都是用来处理数据的 但是过滤器一般用于格式化插入的文本数据
2.如何自定义全局过滤器 Vue.filter(“过滤器名称”, 过滤器处理函数):
3.如何使用全局过滤器(只有这两种使用方式) {{msg | 过滤器名称}} :value=“msg | 过滤器名称”
4.过滤器注意点 4.1只能在插值语法和v-bind中使用 4.2过滤器可以连续使用
<!--这里就是MVVM中的View--> <div id="app"> <!--Vue会把name交给指定的过滤器处理之后, 再把处理之后的结果插入到指定的元素中--> <p>{{name | formartStr1 | formartStr2}}</p> </div> <script> /* 如何自定义一个全局过滤器 通过Vue.filter(); filter方法接收两个参数 第一个参数: 过滤器名称 第二个参数: 处理数据的函数 注意点: 默认情况下处理数据的函数接收一个参数, 就是当前要被处理的数据 * */ Vue.filter("formartStr1", function (value) { // console.log(value); value = value.replace(/学院/g, "大学"); console.log(value); return value; }); Vue.filter("formartStr2", function (value) { // console.log(value); value = value.replace(/大学/g, "幼儿园"); console.log(value); return value; }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { name: "知播渔学院, 指趣学院, 前端学院, 区块链学院" }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { } }); </script>1.自定义全局过滤器的特点 在任何一个Vue实例控制的区域中都可以使用
2.自定义局部过滤器的特点 只能在自定义的那个Vue实例中使用
3.如何自定义一个局部指令 给创建Vue实例时传递的对象添加
filters: { // key: 过滤器名称 // value: 过滤器处理函数 'formartStr': function (value) {} } <!--这里就是MVVM中的View--> <div id="app1"> <p>{{name | formartStr}}</p> </div> <div id="app2"> <p>{{name | formartStr}}</p> </div> <script> /* Vue.filter("formartStr", function (value) { // console.log(value); value = value.replace(/学院/g, "大学"); // console.log(value); return value; }); */ // 这里就是MVVM中的View Model let vue1 = new Vue({ el: '#app1', // 这里就是MVVM中的Model data: { name: "知播渔学院, 指趣学院, 前端学院, 区块链学院" }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { } }); // 这里就是MVVM中的View Model let vue2 = new Vue({ el: '#app2', // 这里就是MVVM中的Model data: { name: "知播渔学院, 指趣学院, 前端学院, 区块链学院" }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部过滤器的 filters: { "formartStr": function (value) { // console.log(value); value = value.replace(/学院/g, "大学"); // console.log(value); return value; } } }); </script>1.如何给Vue控制的元素添加过渡动画 1.1将需要执行动画的元素放到transition组件中 1.2当transition组件中的元素显示时会自动查找.v-enter/.v-enter-active/.v-enter-to类名 当transition组件中的元素隐藏时会自动查找.v-leave/ .v-leave-active/.v-leave-to类名 1.3我们只需要在.v-enter和.v-leave-to中指定动画动画开始的状态 在.v-enter-active和.v-leave-active中指定动画执行的状态 即可完成过渡动画
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>29-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .box{ width: 200px; height: 200px; background: red; } .one-enter{ opacity: 0; } .one-enter-to{ opacity: 1; margin-left: 500px; } .one-enter-active{ transition: all 3s; } .two-enter{ opacity: 0; } .two-enter-to{ opacity: 1; margin-top: 500px; } .two-enter-active{ transition: all 3s; } </style> </head> <body> 1.transition注意点: transition中只能放一个元素, 多个元素无效 如果想给多个元素添加过渡动画, 那么就必须创建多个transition组件 2.初始动画设置 默认情况下第一次进入的时候没没有动画的 如果想一进来就有动画, 我们可以通过给transition添加appear属性的方式 告诉Vue第一次进入就需要显示动画 3.如何给多个不同的元素指定不同的动画 如果有多个不同的元素需要执行不同的过渡动画,那么我们可以通过给transition指定name的方式 来指定"进入之前/进入之后/进入过程中, 离开之前/离开之后/离开过程中"对应的类名 来实现不同的元素执行不同的过渡动画 <!--这里就是MVVM中的View--> <div id="app"> <button @click="toggle">我是按钮</button> <transition appear name="one"> <div class="box" v-show="isShow"></div> <!-- <div class="box" v-show="isShow"></div>--> </transition> <transition appear name="two"> <div class="box" v-show="isShow"></div> </transition> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { isShow: true }, // 专门用于存储监听事件回调函数 methods: { toggle(){ this.isShow = !this.isShow; } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html>通过Vue提供的JS钩子来实现过渡动画
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>30-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .box{ width: 200px; height: 200px; background: red; } .v-enter{ opacity: 0; } .v-enter-to{ opacity: 1; margin-left: 500px; } .v-enter-active{ transition: all 3s; } </style> </head> <body> 1.当前过渡存在的问题 通过transition+类名的方式确实能够实现过渡效果 但是实现的过渡效果并不能保存动画之后的状态 因为Vue内部的实现是在过程中动态绑定类名, 过程完成之后删除类名 正式因为删除了类名, 所以不能保存最终的效果 2.在Vue中如何保存过渡最终的效果 通过Vue提供的JS钩子来实现过渡动画 v-on:before-enter="beforeEnter" 进入动画之前 v-on:enter="enter" 进入动画执行过程中 v-on:after-enter="afterEnter" 进入动画完成之后 v-on:enter-cancelled="enterCancelled" 进入动画被取消 v-on:before-leave="beforeLeave" 离开动画之前 v-on:leave="leave" 离开动画执行过程中 v-on:after-leave="afterLeave" 离开动画完成之后 v-on:leave-cancelled="leaveCancelled" 离开动画被取消 3.JS钩子实现过渡注意点 3.1在动画过程中必须写上el.offsetWidth或者el.offsetHeight 3.2在enter和leave方法中必须调用done方法, 否则after-enter和after-leave不会执行 3.3需要需要添加初始动画, 那么需要把done方法包裹到setTimeout方法中调用 <!--这里就是MVVM中的View--> <div id="app"> <button @click="toggle">我是按钮</button> <!-- 注意点: 虽然我们是通过JS钩子函数来实现过渡动画 但是默认Vue还是回去查找类名, 所以为了不让Vue去查找类名 可以给transition添加v-bind:css="false" --> <transition appear v-bind:css="false" v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:after-enter="afterEnter"> <div class="box" v-show="isShow"></div> </transition> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { isShow: true }, // 专门用于存储监听事件回调函数 methods: { toggle(){ this.isShow = !this.isShow; }, beforeEnter(el){ // 进入动画开始之前 console.log("beforeEnter"); el.style.opacity = "0"; }, enter(el, done){ // 进入动画执行过程中 console.log("enter"); /* 注意点: 如果是通过JS钩子来实现过渡动画 那么必须在动画执行过程中的回调函数中写上 el.offsetWidth / el.offsetHeight * */ // el.offsetWidth; el.offsetHeight; el.style.transition = "all 3s"; /* 注意点: 动画执行完毕之后一定要调用done回调函数 否则后续的afterEnter钩子函数不会被执行 * */ // done(); /* 注意点: 如果想让元素一进来就有动画, 那么最好延迟以下再调用done方法 * */ setTimeout(function () { done(); }, 0); }, afterEnter(el){ // 进入动画执行完毕之后 console.log("afterEnter"); el.style.opacity = "1"; el.style.marginLeft = "500px"; } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html>配合Velocity实现过渡动画
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>31-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .box{ width: 200px; height: 200px; background: red; } </style> </head> <body> 1.配合Velocity实现过渡动画 在Vue中我们除了可以自己实现过渡动画以外, 还可以结合第三方框架实现过渡动画 1.1导入Velocity库 1.2在动画执行过程钩子函数中编写Velocity动画 <!--这里就是MVVM中的View--> <div id="app"> <button @click="toggle">我是按钮</button> <transition appear v-bind:css="false" v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:after-enter="afterEnter"> <div class="box" v-show="isShow"></div> </transition> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { isShow: true }, // 专门用于存储监听事件回调函数 methods: { toggle(){ this.isShow = !this.isShow; }, beforeEnter(el){ }, enter(el, done){ Velocity(el, {opacity: 1, marginLeft: "500px"}, 3000); done(); }, afterEnter(el){ } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html>自定义类名动画
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>32-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .box{ width: 200px; height: 200px; background: red; } .a{ opacity: 0; } .b{ opacity: 1; margin-left: 500px; } .c{ transition: all 3s; } </style> </head> <body> 1.自定义类名动画 在Vue中除了可以使用 默认类名(v-xxx)来指定过渡动画 除了可以使用 自定义类名前缀(yyy-xx)来指定过渡动画(transition name="yyy") 除了可以使用 JS钩子函数来指定过渡动画以外 还可以使用自定义类名的方式来指定过渡动画 enter-class // 进入动画开始之前 enter-active-class // 进入动画执行过程中 enter-to-class // 进入动画执行完毕之后 leave-class // 离开动画开始之前 leave-active-class // 离开动画执行过程中 leave-to-class // 离开动画执行完毕之后 <!--这里就是MVVM中的View--> <div id="app"> <button @click="toggle">我是按钮</button> <transition appear enter-class="a" enter-active-class="c" enter-to-class="b"> <div class="box" v-show="isShow"></div> </transition> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { isShow: true }, // 专门用于存储监听事件回调函数 methods: { toggle(){ this.isShow = !this.isShow; } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html>配合Animate.css实现过渡动画
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>33-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .box{ width: 200px; height: 200px; background: red; } </style> <link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css"> </head> <body> <!-- 1.配合Animate.css实现过渡动画 1.1导入Animate.css库 1.2在执行过程中的属性上绑定需要的类名 --> <!--这里就是MVVM中的View--> <div id="app"> <button @click="toggle">我是按钮</button> <transition appear enter-class="" enter-active-class="animated bounceInRight" enter-to-class=""> <div class="box" v-show="isShow"></div> </transition> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { isShow: true }, // 专门用于存储监听事件回调函数 methods: { toggle(){ this.isShow = !this.isShow; } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html>同时给多个元素添加动画
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>35-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .v-enter{ opacity: 0; } .v-enter-to{ opacity: 1; } .v-enter-active{ transition: all 3s; } .v-leave{ opacity: 1; } .v-leave-to{ opacity: 0; } .v-leave-active{ transition: all 3s; } </style> </head> <body> <!-- 1.如何同时给多个元素添加过渡动画 通过transition可以给单个元素添加过渡动画 如果想给多个元素添加过渡动画, 那么就必须通过transition-group来添加 transition-group和transition的用法一致, 只是一个是给单个元素添加动画, 一个是给多个元素添加动画而已 --> <!--这里就是MVVM中的View--> <div id="app"> <form> <input type="text" v-model="name"> <input type="submit" value="添加" @click.prevent="add"> </form> <ul> <transition-group appear> <li v-for="(person,index) in persons" :key="person.id" @click="del(index)"> <input type="checkbox"> <span>{{index}} --- {{person.name}}</span> </li> </transition-group> </ul> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { persons: [ {name: "zs", id: 1}, {name: "ls", id: 2}, {name: "ww", id: 3} ], name: "" }, // 专门用于存储监听事件回调函数 methods: { add(){ let lastPerson = this.persons[this.persons.length - 1]; let newPerson = {name: this.name, id: lastPerson.id + 1}; // this.persons.push(newPerson); this.persons.unshift(newPerson); this.name = ""; }, del(index){ this.persons.splice(index, 1); } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html>transition-group注意点以及动画混乱的原因
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>36-Vue-过渡动画</title> <script src="js/vue.js"></script> <style> *{ margin: 0; padding: 0; } .v-enter{ opacity: 0; } .v-enter-to{ opacity: 1; } .v-enter-active{ transition: all 3s; } .v-leave{ opacity: 1; } .v-leave-to{ opacity: 0; } .v-leave-active{ transition: all 3s; } </style> </head> <body> <!-- 1.transition-group注意点: 默认情况下transition-group会将动画的元素放到span标签中 我们可以通过tag属性来指定将动画元素放到什么标签中 2.transition-group动画混乱问题 一般情况下组动画出现动画混乱都是因为v-for就地复用导致的 我们只需要保证所有数据key永远是唯一的即可 --> <!--这里就是MVVM中的View--> <div id="app"> <form> <input type="text" v-model="name"> <input type="submit" value="添加" @click.prevent="add"> </form> <!-- <ul>--> <transition-group appear tag="ul"> <li v-for="(person,index) in persons" :key="person.id" @click="del(index)"> <input type="checkbox"> <span>{{index}} --- {{person.name}}</span> </li> </transition-group> <!-- </ul>--> </div> <script> // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { persons: [ {name: "zs", id: 1}, {name: "ls", id: 2}, {name: "ww", id: 3} ], name: "", id: 3 }, // 专门用于存储监听事件回调函数 methods: { add(){ this.id++; // let lastPerson = this.persons[this.persons.length - 1]; let newPerson = {name: this.name, id: this.id}; // this.persons.push(newPerson); this.persons.unshift(newPerson); this.name = ""; }, del(index){ this.persons.splice(index, 1); } }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html>创建组件的其他方式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>38-Vue组件-自定义全局组件</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.创建组件的其它方式 1.1在注册组件的时候, 除了传入一个组件构造器以外, 还可以直接传入一个对象 1.2在编写组件模板的时候, 除了可以在字符串模板中编写以外, 还可以像过去的art-template一样在script中编写 1.3在编写组件模板的时候, 除了可以在script中编写以外, vue还专门提供了一个编写模板的标签template --> <!--这里就是MVVM中的View--> <div id="app"> <!--// 3.3使用注册好的组件--> <abc></abc> </div> <!-- <script id="info" type="text/html"> <div> <img src="images/fm.jpg"/> <p>我是描述信息</p> </div> </script> --> <template id="info"> <div> <img src="images/fm.jpg"/> <p>我是描述信息</p> </div> </template> <script> // 3.1创建组件构造器 /* let Profile = Vue.extend({ // 注意点: 在创建组件指定组件的模板的时候, 模板只能有一个根元素 template: ` <div> <img src="images/fm.jpg"/> <p>我是描述信息</p> </div> ` }); */ /* let obj = { // 注意点: 在创建组件指定组件的模板的时候, 模板只能有一个根元素 template: ` <div> <img src="images/fm.jpg"/> <p>我是描述信息</p> </div> ` }; */ // 3.2注册已经创建好的组件 // 第一个参数: 指定注册的组件的名称 // 第二个参数: 传入已经创建好的组件构造器 // Vue.component("abc", Profile ); // Vue.component("abc", obj ); /* Vue.component("abc", { // 注意点: 在创建组件指定组件的模板的时候, 模板只能有一个根元素 template: ` <div> <img src="images/fm.jpg"/> <p>我是描述信息</p> </div> ` }); */ Vue.component("abc", { // 注意点: 在创建组件指定组件的模板的时候, 模板只能有一个根元素 template: "#info" }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html>自定义组件中的datadata为什么是一个函数? 因为自定义组件可以复用, 为了保证复用时每个组件的数据都是独立的, 所以必须是一个函数
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>41-Vue组件-组件中的data为什么是一个函数</title> <script src="js/vue.js"></script> </head> <body> <!--这里就是MVVM中的View--> <div id="app"> <abc></abc> <abc></abc> <abc></abc> </div> <template id="info"> <div> <button @click="add">累加</button> <p>{{number}}</p> </div> </template> <script> // 自定义全局组件 Vue.component("abc", { template: "#info", /* 组件中的data如果不是通过函数返回的, 那么多个组件就会公用一份数据, 就会导致数据混乱 如果组件中的data是通过函数返回的, 那么每创建一个新的组件, 都会调用一次这个方法 将这个方法返回的数据和当前创建的组件绑定在一起, 这样就有效的避免了数据混乱 * */ data: function () { return { number: 0 } }, methods: { add(){ this.number++; } } }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { } }); </script> </body> </html>组件切换 对于普通的元素我们可以通过v-if来实现切换 对于组件我们也可以通过v-if来实现切换 因为组件的本质就是一个自定义元素
1.如何给组件添加动画? 给组件添加动画和过去给元素添加动画一样 如果是单个组件就使用transition 如果是多个组件就使用transition-group
2.过渡动画注意点 默认情况下进入动画和离开动画是同时执行的, 如果想一个做完之后再做另一个, 需要指定动画模式
1.什么是父子组件? 在一个组件中又定义了其它组件就是父子组件 其实局部组件就是最简单的父子组件, 因为我们说过可以把Vue实例看做是一个大组件 我们在Vue实例中定义了局部组件, 就相当于在大组件里面定义了小组件, 所以实局部组件就是最简单的父子组件
2.如何定义其它的父子组件 前面我们说过, 自定义组件中可以使用data, 可以使用methods. 当然自定义组件中也可以使用components 所以我们也可以在自定义组件中再定义其它组件
1.父子组件数据传递? 在Vue中子组件是不能访问父组件的数据的, 如果子组件想要访问父组件的数据, 必须通过父组件传递
2.如何传递数据 2.1在父组件中通过v-bind传递数据 传递格式 v-bind:自定义接收名称 = “要传递数据” 2.2在子组件中通过props接收数据 接收格式 props: [“自定义接收名称”]
1.父子组件方法传递? 在Vue中子组件是不能访问父组件的方法的, 如果子组件想要访问父组件的方法, 必须通过父组件传递
2.如何传递方法 2.1在父组件中通过v-on传递方法 传递格式 v-on:自定义接收名称 = “要传递方法” 2.2在子组件中自定义一个方法 2.3在自定义方法中通过 this.$emit(‘自定义接收名称’);触发传递过来的方法
注意点: 和传递数据不同, 如果传递的是方法, 那么在子组件中不需要接收 如果传递的是方法, 那么需要在子组件中自定义一个方法 如果传递的是方法, 那么在子组件中直接使用自定义的方法即可 如果传递的是方法, 那么需要在子组件自定义的方法中通过 this.$emit(“自定义接收的名称”)的方法来触发父组件传递过来的方法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>49-Vue组件-子组件传递数据给父组件</title> <script src="js/vue.js"></script> </head> <body> 1.如何将子组件数据传递给父组件 既然我们可以将父组件的方法传递给子组件 既然我们可以在子组件中调用父组件中的方法, 那么我们就可以在调用方法的时候给方法传递参数 传递的参数, 就是我们需要传递的数据 <!--这里就是MVVM中的View--> <div id="app"> <father></father> </div> <template id="father"> <div> <button @click="say">我是按钮</button> <!--这里通过parentsay将父组件的say方法传递给了子组件--> <son @parentsay="say"></son> </div> </template> <template id="son"> <div> <button @click="sonFn">我是按钮</button> </div> </template> <script> // 父组件 Vue.component("father", { template: "#father", methods: { say(data){ // alert("www.it666.com"); console.log(data); } }, // 子组件 components: { "son": { template: "#son", methods: { sonFn(){ // 第一个参数: 需要调用的函数名称 // 后续的参数: 给调用的函数传递的参数 this.$emit("parentsay", "知播渔"); } } } } }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { } }); </script> </body> </html>1.组件中的命名注意点 1.1注册组件的时候使用了"驼峰命名", 那么在使用时需要转换成"短横线分隔命名" 例如: 注册时: myFather -> 使用时: my-father 1.2在传递参数的时候如果想使用"驼峰名称", 那么就必须写"短横线分隔命名" 例如: 传递时: parent-name=“name” -> 接收时: props: [“parentName”] 1.3在传递方法的时候不能使用"驼峰命名", 只能用"短横线分隔命名" @parent-say=“say” -> this.$emit(“parent-say”);
1.数据和方法的多级传递 在Vue中如果儿子想使用爷爷的数据, 必须一层一层往下传递 在Vue中如果儿子想使用爷爷的方法, 必须一层一层往下传递
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>51-Vue组件-数据和方法的多级传递</title> <script src="js/vue.js"></script> </head> <body> <!--这里就是MVVM中的View--> <div id="app"> <grandfather></grandfather> </div> <template id="grandfather"> <div> <p>{{name}}</p> <button @click="say">我是按钮</button> <father :gfname="name" @gfsay="say"></father> </div> </template> <template id="father"> <div> <p>{{gfname}}</p> <button @click="fatherFn">我是按钮</button> <son :fname="gfname" @fsay="fatherFn"></son> </div> </template> <template id="son"> <div> <p>{{fname}}</p> <button @click="sonFn">我是按钮</button> </div> </template> <script> // 爷爷组件 Vue.component("grandfather", { template: "#grandfather", data: function(){ return { name: "lnj" } }, methods: { say(){ console.log("我是爷爷的方法"); } }, // 爸爸组件 components: { "father": { template: "#father", props: ["gfname"], methods:{ fatherFn(){ this.$emit("gfsay"); } }, // 儿子组件 components: { "son": { template: "#son", props: ["fname"], methods: { sonFn(){ this.$emit("fsay"); } }, } } } } }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { } }); </script> </body> </html>1.什么是插槽? 默认情况下使用子组件时在子组件中编写的元素是不会被渲染的 如果子组件中有部分内容是使用时才确定的, 那么我们就可以使用插槽 插槽就是在子组件中放一个"坑", 以后由父组件来"填"
1.什么是匿名插槽 没有名字的插槽, 会利用使用时指定的能容替换整个插槽 注意点: 如果有多个匿名插槽, 每一个匿名插槽都会被指定的内容替换 虽然写多个匿名插槽不会报错, 但是在企业开发中推荐只能有一个匿名插槽
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>52-Vue组件-匿名插槽</title> <script src="js/vue.js"></script> </head> <body> <!--这里就是MVVM中的View--> <div id="app"> <father></father> </div> <template id="father"> <div> <!--需求: 在使用子组件的时候给子组件动态的添加一些内容--> <son> <!--注意点: 默认情况下是不能在使用子组件的时候, 给子组件动态的添加内容的 如果想在使用子组件的时候, 给子组件动态的添加内容, 那么就必须使用插槽--> <div>我是追加的内容1</div> <div>我是追加的内容2</div> <div>我是追加的内容3</div> </son> </div> </template> <template id="son"> <div> <div>我是头部</div> <!--这里的slot标签就是插槽, 插槽其实就是一个坑 只要有了这个坑, 那么以后使用者就可以根据自己的需要来填这个坑--> <!--注意点: 插槽可以指定默认数据, 如果使用者没有填这个坑, 那么就会显示默认数据 如果使用者填了这个坑, 那么就会利用使用者天坑的内容替换整个插槽--> <!--注意点: 插槽是可以指定名称的, 默认情况下如果没有指定名称, 我们称之为 匿名插槽--> <!--匿名插槽的特点: 有多少个匿名插槽, 填充的数据就会被拷贝几份 虽然我们可以指定多个匿名插槽, 但是在企业开发中推荐只写一个匿名插槽--> <slot>我是默认数据</slot> <!-- <slot>我是默认数据</slot>--> <div>我是底部</div> </div> </template> <script> // 父组件 Vue.component("father", { template: "#father", // 子组件 components: { "son": { template: "#son", } } }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { } }); </script> </body> </html>1.什么是具名插槽 默认情况下有多少个匿名插槽, 我们填充的数据就会被拷贝多少份 这导致了所有插槽中填充的内容都是一样的 那么如果我们想给不同的插槽中填充不同的内容怎么办呢? 这个时候就可以使用具名插槽
2.具名插槽使用 通过插槽的name属性给插槽指定名称 在使用时可以通过slot="name"方式, 指定当前内容用于替换哪一个插槽
注意点: 如果没有指定要替换哪个插槽中的内容, 则不会被替换
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>53-Vue组件-具名插槽</title> <script src="js/vue.js"></script> </head> <body> <!--这里就是MVVM中的View--> <div id="app"> <father></father> </div> <template id="father"> <div> <son> <!--这里通过slot属性告诉Vue,当前的内容是要填充到哪一个插槽中的--> <div slot="one">我是追加的内容1</div> <div slot="one">我是追加的内容11</div> <div slot="two">我是追加的内容2</div> <div slot="two">我是追加的内容22</div> </son> </div> </template> <template id="son"> <div> <div>我是头部</div> <!--可以在定义插槽的时候给插槽添加一个name属性, 通过这个name属性来指定插槽的名称 如通插槽指定了名称, 那么我们就称之为具名插槽--> <!--注意点: 默认情况下填充的内容是不会被填充到具名插槽中的, 只有给填充的内容指定了要填充到哪一个具名插槽之后, 才会将填充的内容填充到具名插槽中--> <slot name="one">我是默认内容</slot> <slot name="two">我是默认内容</slot> <div>我是底部</div> </div> </template> <script> // 父组件 Vue.component("father", { template: "#father", // 子组件 components: { "son": { template: "#son", } } }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { } }); </script> </body> </html>1.什么是v-slot指令? v-slot指令是Vue2.6中用于替代slot属性的一个指令 在Vue2.6之前, 我们通过slot属性告诉Vue当前内容填充到哪一个具名插槽 从Vue2.6开始, 我们通过v-slot指令告诉Vue当前内容填充到哪一个具名插槽
注意点: v-slot指令只能用在template标签上 可以使用#号替代v-slot:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>54-Vue组件-v-slot指令</title> <script src="js/vue.js"></script> </head> <body> <!--这里就是MVVM中的View--> <div id="app"> <father></father> </div> <template id="father"> <div> <son> <!--这里通过slot属性告诉Vue,当前的内容是要填充到哪一个插槽中的--> <!-- <div slot="one">我是追加的内容1</div> <div slot="one">我是追加的内容11</div> <div slot="two">我是追加的内容2</div> <div slot="two">我是追加的内容22</div> --> <!-- <template v-slot:one> <div>我是追加的内容1</div> <div>我是追加的内容11</div> </template> <template v-slot:two> <div>我是追加的内容2</div> <div>我是追加的内容22</div> </template> --> <!--v-bind: : v-on: @--> <template #one> <div>我是追加的内容1</div> <div>我是追加的内容11</div> </template> <template #two> <div>我是追加的内容2</div> <div>我是追加的内容22</div> </template> </son> </div> </template> <template id="son"> <div> <div>我是头部</div> <slot name="one">我是one默认内容</slot> <slot name="two">我是two默认内容</slot> <div>我是底部</div> </div> </template> <script> // 父组件 Vue.component("father", { template: "#father", // 子组件 components: { "son": { template: "#son", } } }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { } }); </script> </body> </html>1.什么是作用域插槽 作用域插槽就是带数据的插槽, 就是让父组件在填充子组件插槽内容时也能使用子组件的数据
2.如何使用作用域插槽 2.1在slot中通过 v-bind:数据名称=“数据名称” 方式暴露数据 2.2在父组件中通过 接收数据 2.3在父组件的中通过 作用域名称.数据名称 方式使用数据
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>55-Vue组件-作用域插槽</title> <script src="js/vue.js"></script> </head> <body> <!--这里就是MVVM中的View--> <div id="app"> <father></father> </div> <template id="father"> <div> <son> <!-- <div>我是填充的内容 {{names}}</div>--> <!-- slot-scope="abc"作用: 接收子组件插槽暴露的数据 --> <!-- 作用域插槽的应用场景: 子组件提供数据, 父组件决定如何渲染 --> <template slot-scope="abc"> <!-- <div>我是填充的内容 {{abc.names}}</div>--> <li v-for="(name, index) in abc.names">{{name}}</li> </template> </son> </div> </template> <template id="son"> <div> <div>我是头部 {{names}}</div> <!-- v-bind:names="names"作用: 将当前子组件的names数据暴露给父组件 --> <slot v-bind:names="names">我是默认内容 {{names}}</slot> <div>我是底部</div> </div> </template> <script> // 父组件 Vue.component("father", { template: "#father", // 子组件 components: { "son": { template: "#son", data:function () { return { names: ["zs", "ls", "ww", "zl"] } } } } }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { } }); </script> </body> </html>在 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。 它取代了 slot 和 slot-scope
也就是说我们除了可以通过v-slot指令告诉Vue内容要填充到哪一个具名插槽中 还可以通过v-slot指令告诉Vue如何接收作用域插槽暴露的数据
v-slot:插槽名称=“作用域名称”
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>56-Vue组件-v-slot指令</title> <script src="js/vue.js"></script> </head> <body> <!--这里就是MVVM中的View--> <div id="app"> <father></father> </div> <template id="father"> <div> <son> <!-- <template slot-scope="abc"> <li v-for="(name, index) in abc.names">{{name}}</li> </template> --> <!-- <template v-slot:default="abc"> <li v-for="(name, index) in abc.names">{{name}}</li> </template> --> <!-- <template #default="abc"> <li v-for="(name, index) in abc.names">{{name}}</li> </template> --> <template #one="abc"> <li v-for="(name, index) in abc.names">{{name}}</li> </template> </son> </div> </template> <template id="son"> <div> <div>我是头部 {{names}}</div> <!-- <slot v-bind:names="names">我是默认内容 {{names}}</slot>--> <slot name="one" v-bind:names="names">我是默认内容 {{names}}</slot> <div>我是底部</div> </div> </template> <script> // 父组件 Vue.component("father", { template: "#father", // 子组件 components: { "son": { template: "#son", data:function () { return { names: ["zs", "ls", "ww", "zl"] } } } } }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { } }); </script> </body> </html>1.什么是Vuex? vuex 是 Vue 配套的 公共数据管理工具,它可以把一些共享的数据,保存到 vuex 中, 方便整个程序中的任何组件直接获取或修改我们的公共数据
注意点: 只有需要共享的才放到vuex上, 不需要共享的数据依然放到组件自身的data上
1.当前在企业开发中我们遇到了两个问题: 1.如果想要在子组件中使用祖先组件中的数据, 那么就必须一层一层的传递(非常麻烦) 2.兄弟组件之间不能直接传递数据, 如果兄弟组件之间想要传递数据, 那么就必须借助父组件(非常麻烦) 解决方案: 使用Vuex
2.什么是Vuex? vuex 是 Vue 配套的 公共数据管理工具,我们可以将共享的数据保存到 vuex 中, 方便整个程序中的任何组件都可以获取和修改vuex中保存的公共数据
注意点: 必须在引入Vue之后再引入Vuex 只有需要共享的才放到vuex上, 不需要共享的数据依然放到组件自身的data上
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>58-Vuex-共享数据</title> <script src="js/vue.js"></script> <!--1.导入Vuex--> <!--注意点: 在导入Vuex之前必须先导入Vue--> <script src="js/vuex.js"></script> </head> <body> <!--这里就是MVVM中的View--> <div id="app"> <grandfather></grandfather> </div> <template id="grandfather"> <div> <p>{{this.$store.state.msg}}</p> <father></father> </div> </template> <template id="father"> <div> <!--4.在使用Vuex中保存的共享数据的时候, 必须通过如下的格式来使用--> <p>{{this.$store.state.msg}}</p> <son></son> </div> </template> <template id="son"> <div> <p>{{this.$store.state.msg}}</p> </div> </template> <script> // 2.创建Vuex对象 const store = new Vuex.Store({ // 这里的state就相当于组件中的data, 就是专门用于保存共享数据的 state: { msg: "知播渔" }, }); // 爷爷组件 Vue.component("grandfather", { template: "#grandfather", // 3.在祖先组件中添加store的key保存Vuex对象 // 只要祖先组件中保存了Vuex对象 , 那么祖先组件和所有的后代组件就可以使用Vuex中保存的共享数据了 store: store, // 爸爸组件 components: { "father": { template: "#father", // 儿子组件 components: { "son": { template: "#son", } } } } }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { }, }); </script> </body> </html>1.什么是Vuex的getters? Vuex的getters属性就和组件的计算属性一样, 会将数据缓存起来, 只有数据发生变化才会重新计算
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>60-Vuex-getters</title> <script src="js/vue.js"></script> <script src="js/vuex.js"></script> </head> <body> <!-- 1.什么是Vuex的getters? Vuex的getters属性就和组件的计算属性一样, 会将数据缓存起来, 只有数据发生变化才会重新计算 --> <!--这里就是MVVM中的View--> <div id="app"> <father></father> </div> <template id="father"> <div> <!-- {{formart}}--> <!-- {{formart}}--> <!-- {{formart}}--> <!-- {{this.$store.state.msg}} "www.it666.com"--> <!-- {{this.$store.state.msg}} "www.it666.com"--> <!-- {{this.$store.state.msg}} "www.it666.com"--> {{this.$store.getters.formart}} {{this.$store.getters.formart}} {{this.$store.getters.formart}} </div> </template> <script> const store = new Vuex.Store({ // state: 用于保存共享数据 state: { msg: "知播渔" }, // mutations: 用于保存修改共享数据的方法 mutations: { }, getters: { formart(state){ console.log("getters方法被执行了"); return state.msg + "www.it666.com" } } }); // 爸爸组件 Vue.component("father", { template: "#father", store: store, // data: function () { // return { // msg: "知播渔" // } // }, // computed: { // formart(){ // console.log("计算属性的方法被执行了"); // return this.msg + "www.it666.com"; // } // } }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { } }); </script> </body> </html>1.什么是Vue Router? Vue Router和v-if/v-show一样, 是用来切换组件的显示的 v-if/v-show是标记来切换(true/false) Vue Router用哈希来切换(#/xxx) 比v-if/v-show强大的是Vue Router不仅仅能够切换组件的显示, 还能够在切换的时候传递参数
2.Vue Router使用 2.1导入Vue Router 2.2定义路由规则 2.3根据路由规则创建路由对象 2.4将路径对象挂载到Vue实例中 2.5修改URL哈希值 2.6通过渲染匹配的组件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>62-VueRouter-基本使用</title> <style> *{ margin: 0; padding: 0; } .onepage, .twopage{ width: 500px; height: 500px; } .onepage{ background: pink; } .twopage{ background: skyblue; } /*.router-link-active{*/ /* background: red;*/ /*}*/ .nj-active{ background: skyblue; } </style> <script src="js/vue.js"></script> <!--1.导入Vue Router--> <!--注意点: 必须先导入Vue之后再导入Vue Router--> <script src="js/vue-router.js"></script> </head> <body> <!-- 1.什么是router-link? 通过a标签确实能设置URL的hash,但是这种方式并不专业 在Vue Router中提供了一个专门用于设置hash的标签 router-link 2.router-link特点 默认情况下Vue会将router-link渲染成a标签, 但是我们可以通过tag来指定到底渲染成什么 3.给router-link设置选中样式 默认情况下我们可以通过重写router-link-active类名来实现设置选中样式 但是我们也可以通过linkActiveClass来指定选中样式 4.重定向路由 { path: '被重定向值', redirect: '重定向之后的值' } --> <!--这里就是MVVM中的View--> <div id="app"> <!-- <a href="#/one">切换到第一个界面</a> <a href="#/two">切换到第二个界面</a>--> <!-- 如果是通过router-link来设置URL的HASH值, 那么不用写#, 那么是通过to属性来设置HASH值 --> <!-- 默认情况下Vue在渲染router-link的时候, 是通过a标签来渲染的 如果在企业开发中不想使用a标签来渲染, 那么可以通过tag属性来告诉vue通过什么标签来渲染 --> <router-link to="/one" tag="button">切换到第一个界面</router-link> <router-link to="/two" tag="button">切换到第二个界面</router-link> <!-- 路由出口 --> <!-- 路由匹配到的组件将渲染在这里 --> <router-view></router-view> </div> <template id="one"> <div class="onepage"> <p>我是第一个界面</p> </div> </template> <template id="two"> <div class="twopage"> <p>我是第二个界面</p> </div> </template> <script> // 1.定义组件 const one = { template: "#one" }; const two = { template: "#two" }; // 2.定义切换的规则(定义路由规则) const routes = [ // 重定向路由 { path: '/', redirect: '/two' }, // 数组中的每一个对象就是一条规则 { path: '/one', component: one }, { path: '/two', component: two } ]; // 3.根据自定义的切换规则创建路由对象 const router = new VueRouter({ routes: routes, // 指定导航激活状态样式类名 linkActiveClass: "nj-active" }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 4.将创建好的路由对象绑定到Vue实例上 router: router, // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { one: one, two: two } }); </script> </body> </html>1.Vue Router传递参数 只要将Vue Router挂载到了Vue实例对象上, 我们就可以通过vue.$route拿到路由对象 只要能拿到路由对象, 就可以通过路由对象拿到传递的参数
方式一: 通过URL参数参数(?key=value&key=value), 通过this.$route.query获取 方式二: 通过占位符传递(路由规则中/:key/:key, 路径中/value/value), 通过this.$route.params获取 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>63-VueRouter-参数传递</title> <style> *{ margin: 0; padding: 0; } .onepage, .twopage{ width: 500px; height: 500px; } .onepage{ background: pink; } .twopage{ background: skyblue; } /*.router-link-active{*/ /* background: red;*/ /*}*/ .nj-active{ background: skyblue; } </style> <script src="js/vue.js"></script> <!--1.导入Vue Router--> <script src="js/vue-router.js"></script> </head> <body> <!-- 1.Vue Router传递参数 只要将Vue Router挂载到了Vue实例对象上, 我们就可以通过vue.$route拿到路由对象 只要能拿到路由对象, 就可以通过路由对象拿到传递的参数 方式一: 通过URL参数参数(?key=value&key=value), 通过this.$route.query获取 方式二: 通过占位符传递(路由规则中/:key/:key, 路径中/value/value), 通过this.$route.params获取 --> <!--这里就是MVVM中的View--> <div id="app"> <!-- 第一种传递参数的方式: 通过URL参数的方式传递 在指定HASH的时候, 通过?key=value&key=value的方式传递 在传递的组件的生命周期方法中通过 this.$route.query的方式来获取 --> <router-link to="/one?name=lnj&age=33" tag="button">切换到第一个界面</router-link> <!-- 第二种传递参数的方式: 通过路由规则中的占位符传递 在指定路由规则的时候通过/:key/:key的方式来指定占位符 在指定HASH的时候, 通过/value/value的方式来传递值 在传递的组件的生命周期方法中通过 this.$route.params的方式来获取 --> <router-link to="/two/zs/66" tag="button">切换到第二个界面</router-link> <!-- 路由出口 --> <!-- 路由匹配到的组件将渲染在这里 --> <router-view></router-view> </div> <template id="one"> <div class="onepage"> <p>我是第一个界面</p> </div> </template> <template id="two"> <div class="twopage"> <p>我是第二个界面</p> </div> </template> <script> // 1.定义组件 const one = { template: "#one", created: function () { console.log(this.$route); console.log(this.$route.query.name); console.log(this.$route.query.age); } }; const two = { template: "#two", created: function () { console.log(this.$route); console.log(this.$route.params.name); console.log(this.$route.params.age); } }; // 2.定义切换的规则(定义路由规则) const routes = [ // 数组中的每一个对象就是一条规则 { path: '/one', component: one }, { path: '/two/:name/:age', component: two } ]; // 3.根据自定义的切换规则创建路由对象 const router = new VueRouter({ routes: routes, linkActiveClass: "nj-active" }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 4.将创建好的路由对象绑定到Vue实例上 router: router, // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { one: one, two: two } }); // console.log(vue.$route); </script> </body> </html>1.什么是嵌套路由? 嵌套路由也称之为子路由, 就是在被切换的组件中又切换其它子组件 例如: 在one界面中又有两个按钮, 通过这两个按钮进一步切换one中的内容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>64-VueRouter-嵌套路由</title> <style> *{ margin: 0; padding: 0; } .onepage, .twopage{ width: 500px; height: 500px; } .onepage{ background: pink; } .twopage{ background: skyblue; } .onesub1page, .onesub2page{ width: 100%; height: 300px; } .onesub1page{ background: orangered; } .onesub2page{ background: blueviolet; } .nj-active{ background: skyblue; } </style> <script src="js/vue.js"></script> <!--1.导入Vue Router--> <script src="js/vue-router.js"></script> </head> <body> <!-- 1.什么是嵌套路由? 嵌套路由也称之为子路由, 就是在被切换的组件中又切换其它子组件 例如: 在one界面中又有两个按钮, 通过这两个按钮进一步切换one中的内容 --> <!--这里就是MVVM中的View--> <div id="app"> <router-link to="/one" tag="button">切换到第一个界面</router-link> <router-link to="/two" tag="button">切换到第二个界面</router-link> <!-- 路由出口 --> <!-- 路由匹配到的组件将渲染在这里 --> <router-view></router-view> </div> <template id="one"> <div class="onepage"> <p>我是第一个界面</p> <router-link to="/one/onesub1" tag="button">切换到第一个子界面</router-link> <router-link to="/one/onesub2" tag="button">切换到第二个子界面</router-link> <!-- 路由出口 --> <!-- 路由匹配到的组件将渲染在这里 --> <router-view></router-view> </div> </template> <template id="onesub1"> <div class="onesub1page"> <p>我是第一个界面子界面1</p> </div> </template> <template id="onesub2"> <div class="onesub2page"> <p>我是第一个界面子界面2</p> </div> </template> <template id="two"> <div class="twopage"> <p>我是第二个界面</p> </div> </template> <script> // 1.定义组件 const onesub1 = { template: "#onesub1", }; const onesub2 = { template: "#onesub2", }; const one = { template: "#one", components:{ onesub1:onesub1, onesub2: onesub2 } }; const two = { template: "#two" }; // 2.定义切换的规则(定义路由规则) const routes = [ // 数组中的每一个对象就是一条规则 { path: '/one', component: one, children:[ { // 注意点: 如果是嵌套路由(子路由), 那么不用写一级路径的地址, 并且也不用写/ path: "onesub1", component: onesub1 }, { // 注意点: 如果是嵌套路由(子路由), 那么不用写一级路径的地址, 并且也不用写/ path: "onesub2", component: onesub2 } ] }, // { path: '/one/onesub1', component: onesub1 }, // { path: '/one/onesub2', component: onesub2 }, { path: '/two', component: two } ]; // 3.根据自定义的切换规则创建路由对象 const router = new VueRouter({ routes: routes, linkActiveClass: "nj-active" }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 4.将创建好的路由对象绑定到Vue实例上 router: router, // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { one: one, two: two } }); // console.log(vue.$route); </script> </body> </html>1.什么是Watch属性? Watch属性是专门用于监听数据变化的, 只要数据发生了变化, 就会自动调用对应数据的回调方法
2.Watch监听路由变化 Watch属性不仅仅能够监听数据的变化, 还能够监听路由地址的变化 在企业开发中我们可以通过Watch来判断当前界面是从哪个界面跳转过来的
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>67-VueRouter-Watch属性</title> <script src="js/vue.js"></script> <script src="js/vue-router.js"></script> </head> <body> <!-- 1.什么是Watch属性? Watch属性是专门用于监听数据变化的, 只要数据发生了变化, 就会自动调用对应数据的回调方法 2.Watch监听路由变化 Watch属性不仅仅能够监听数据的变化, 还能够监听路由地址的变化 在企业开发中我们可以通过Watch来判断当前界面是从哪个界面跳转过来的 --> <!--这里就是MVVM中的View--> <div id="app"> <!-- <input type="text" v-model="num1" @keyup="change1">--> <!--<input type="text" v-model="num1"> <span>+</span>--> <!-- <input type="text" v-model="num2" @keyup="change2">--> <!--<input type="text" v-model="num2"> <span>=</span> <input type="text" disabled v-model="res">--> <a href="#/one">切换到第一个界面</a> <a href="#/two">切换到第二个界面</a> <router-view></router-view> </div> <template id="one"> <div class="onepage"> <p>我是第一个界面</p> </div> </template> <template id="two"> <div class="twopage"> <p>我是第二个界面</p> </div> </template> <script> // 1.定义组件 const one = { template: "#one", }; const two = { template: "#two" }; // 2.定义切换的规则(定义路由规则) const routes = [ // 数组中的每一个对象就是一条规则 { path: '/one', component: one }, { path: '/two', component: two } ]; // 3.根据自定义的切换规则创建路由对象 const router = new VueRouter({ routes: routes }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 4.将创建好的路由对象绑定到Vue实例上 router: router, watch: { // 可以通过watch监听Model中数据的变化, 只要数据发生变化, 就会自动调用对应的回调函数 num1: function (newValue, oldValue) { // console.log(this.num1); // console.log(newValue, oldValue); this.res = parseInt(this.num1) + parseInt(this.num2) }, num2: function (newValue, oldValue) { this.res = parseInt(this.num1) + parseInt(this.num2) }, // 可以通过watch监听路由地址的变化, 只要路由地址发生变化, 就会自动调用对应的回调函数 "$route.path": function (newValue, oldValue) { console.log(newValue, oldValue); } }, // 这里就是MVVM中的Model data: { num1: 0, num2: 0, res: 0 }, // 专门用于存储监听事件回调函数 methods: { change1(){ this.res = parseInt(this.num1) + parseInt(this.num2) }, change2(){ this.res = parseInt(this.num1) + parseInt(this.num2) } }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { one: one, two: two } }); console.log(vue.$route); </script> </body> </html>1.什么是生命周期方法? 和wbpack生命周期方法一样, 都是在从生到死的特定阶段调用的方法 PS: 生命周期钩子 = 生命周期函数 = 生命周期事件 2.Vue生命周期方法分类 2.1创建期间的生命周期方法 beforeCreate:在调用beforeCreate的时候, 仅仅表示Vue实例刚刚被创建出来 此时此刻还没有初始化好Vue实例中的数据和方法, 所以此时此刻还不能访问Vue实例中保存的数据和方法 created:在调用created的时候, 是我们最早能够访问Vue实例中保存的数据和方法的地方 beforeMount:在调用beforeMount的时候, 表示Vue已经编译好了最终模板, 但是还没有将最终的模板渲染到界面上 mounted:在调用mounted的时候, 表示Vue已经完成了模板的渲染, 表示我们已经可以拿到界面上渲染之后的内容了 2.2运行期间的生命周期方法 beforeUpdate:在调用beforeUpdate的时候, 表示Vue实例中保存的数据被修改了 注意点: 只有保存的数据被修改了才会调用beforeUpdate, 否则不会调用 注意点: 在调用beforeUpdate的时候, 数据已经更新了, 但是界面还没有更新 updated:在调用updated的时候, 表示Vue实例中保存的数据被修改了, 并且界面也同步了修改的数据了 也就是说: 数据和界面都同步更新之后就会调用updated 2.3销毁期间的生命周期方法 beforeDestroy:在调用beforeDestroy的时候, 表示当前组件即将被销毁了 注意点: 只要组件不被销毁, 那么beforeDestroy就不会调用 beforeDestroy函数是我们最后能够访问到组件数据和方法的函数 ** destroyed**:在调用destroyed的时候, 表示当前组件已经被销毁了 注意点: 只要组件不被销毁, 那么destroyed就不会调用 不要在这个生命周期方法中再去操作组件中数据和方法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>68-Vue-生命周期方法</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.什么是生命周期方法? 和wbpack生命周期方法一样, 都是在从生到死的特定阶段调用的方法 PS: 生命周期钩子 = 生命周期函数 = 生命周期事件 2.Vue生命周期方法分类 2.1创建期间的生命周期方法 beforeCreate: created: beforeMount: mounted: 2.2运行期间的生命周期方法 beforeUpdate: updated: 2.3销毁期间的生命周期方法 beforeDestroy: destroyed: --> <!--这里就是MVVM中的View--> <div id="app"> <p>{{msg}}</p> </div> <!-- <div id="app"> <p>知播渔</p> </div> --> <script> // 这里就是MVVM中的View Model let vue = new Vue({ beforeCreate:function(){ /* 在调用beforeCreate的时候, 仅仅表示Vue实例刚刚被创建出来 此时此刻还没有初始化好Vue实例中的数据和方法, 所以此时此刻还不能访问Vue实例中保存的数据和方法 * */ // console.log(this.msg); // console.log(this.say); }, created:function(){ /* 在调用created的时候, 是我们最早能够访问Vue实例中保存的数据和方法的地方 * */ // console.log(this.msg); // console.log(this.say); }, beforeMount:function(){ /* 在调用beforeMount的时候, 表示Vue已经编译好了最终模板, 但是还没有将最终的模板渲染到界面上 * */ // console.log(document.querySelector("p").innerHTML); // console.log(document.querySelector("p").innerText); }, mounted:function(){ /* 在调用mounted的时候, 表示Vue已经完成了模板的渲染, 表示我们已经可以拿到界面上渲染之后的内容了 * */ console.log(document.querySelector("p").innerHTML); console.log(document.querySelector("p").innerText); }, el: '#app', // 专门用于监听数据变化的 watch: { }, // 这里就是MVVM中的Model data: { msg: "知播渔" }, // 专门用于存储监听事件回调函数 methods: { say(){ console.log("say"); } }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { } }); </script> </body> </html>1.Vue特殊特性 Vue特点: 数据驱动界面更新, 无需操作DOM来更新界面 也就是说Vue不推荐我们直接操作DOM, 但是在企业开发中有时候我们确实需要拿到DOM操作DOM 那么如果不推荐使用原生的语法获取DOM, 我们应该如何获取DOM? 在Vue中如果想要拿到DOM元素我们可以通过ref来获取
2.ref使用 2.1在需要获取的元素上添加ref属性. 例如:
我是段落</> 2.2在使用的地方通过 this. r e f s . x x x 获 取 , 例 如 t h i s . refs.xxx获取, 例如 this. refs.xxx获取,例如this.ref.myppp
3.ref特点 ref添加到元素DOM上, 拿到的就是元素DOM ref添加到组件上, 拿到的就是组件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>71-Vue-特殊特性</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.Vue特殊特性 Vue特点: 数据驱动界面更新, 无需操作DOM来更新界面 也就是说Vue不推荐我们直接操作DOM, 但是在企业开发中有时候我们确实需要拿到DOM操作DOM 那么如果不推荐使用原生的语法获取DOM, 我们应该如何获取DOM? 在Vue中如果想要拿到DOM元素我们可以通过ref来获取 2.ref使用 2.1在需要获取的元素上添加ref属性. 例如: <p ref="mypp">我是段落</> 2.2在使用的地方通过 this.$refs.xxx获取, 例如 this.$ref.myppp 3.ref特点 ref添加到元素DOM上, 拿到的就是元素DOM ref添加到组件上, 拿到的就是组件 --> <!--这里就是MVVM中的View--> <div id="app"> <button @click="myFn">我是按钮</button> <p ref="myppp">我是原生的DOM</p> <one id="myOne" ref="myOne"></one> </div> <template id="one"> <div> <p>我是组件</p> </div> </template> <script> Vue.component("one", { template: "#one", data: function(){ return { msg: "知播渔" } }, methods: { say(){ console.log("say"); } }, }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', // 专门用于监听数据变化的 watch: { }, // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { myFn(){ // 注意点: 如果是通过原生的语法来获取元素, 无论是原生的元素还是自定义的组件, 拿到的都是原生的元素 // 注意点: 并且VUE官方并不推荐我们这样获取 // console.log(document.querySelector("p")); // console.log(document.querySelector("#myOne")); // 在Vue中如果想获取原生的元素或者获取自定义的组件, 可以通过ref来获取 // 注意点: ref如果是添加给元素的元素, 那么拿到的就是元素的元素 // ref如果是添加给自定义的组件, 那么拿到的就是自定义的组件 console.log(this.$refs); console.log(this.$refs.myppp); console.log(this.$refs.myOne); console.log(this.$refs.myOne.msg); console.log(this.$refs.myOne.say); } }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { } }); </script> </body> </html>1.Vue渲染组件的两种方式 1.1先定义注册组件, 然后在Vue实例中当做标签来使用 1.2先定义注册组件, 然后通过Vue实例的render方法来渲染
2.两种渲染方法的区别 1.1当做标签来渲染, 不会覆盖Vue实例控制区域 1.2通过render方法来渲染, 会覆盖Vue实例控制区域
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>72-Vue-组件渲染方式</title> <script src="js/vue.js"></script> </head> <body> <!-- 1.Vue渲染组件的两种方式 1.1先定义注册组件, 然后在Vue实例中当做标签来使用 1.2先定义注册组件, 然后通过Vue实例的render方法来渲染 2.两种渲染方法的区别 1.1当做标签来渲染, 不会覆盖Vue实例控制区域 1.2通过render方法来渲染, 会覆盖Vue实例控制区域 --> <!--这里就是MVVM中的View--> <div id="app"> <!-- <one></one>--> </div> <template id="one"> <div> <p>我是组件222</p> </div> </template> <script> Vue.component("one", { template: "#one" }); // 这里就是MVVM中的View Model let vue = new Vue({ el: '#app', render: function(createElement){ let html = createElement("one"); return html; }, // 专门用于监听数据变化的 watch: { }, // 这里就是MVVM中的Model data: { }, // 专门用于存储监听事件回调函数 methods: { }, // 专门用于定义计算属性的 computed: { }, // 专门用于定义局部组件的 components: { } }); </script> </body> </html>1.什么是Vue-CLI(Command Line Interface)? Vue-CLI是vue官方提供的脚手架工具, 默认已经帮我们搭建好了一套利用webpack管理vue的项目结构
2.如何安装Vue-cli和使用Vue-CLI? 安装脚手架工具: npm install -g @vue/cli 检查是否安装成功: vue --version 通过脚手架创建项目: vue create project-name
3.通过Vue-CLI生成的项目结构解读 3.1在Vue-CLI2.x中生成的项目结构中我们能够看到build文件夹和config文件夹 这两个文件夹中存储了webpack相关的配置, 我们可以针对项目需求修改webpack配置 3.2在Vue-CLI3以后生成的项目结构中已经没有了build文件夹和config文件夹 这么做的目的是为了化繁为简, 让初学者不用关心webpack, 只用关心如何使用Vue
node_modules文件夹: 存储了依赖的相关的包 public文件夹: 任何放置在 public 文件夹的静态资源都会被简单的复制, 而不经过 webpack。你需要通过绝对路径来引用它们 一般用于存储一些永远不会改变的静态资源或者webpack不支持的第三方库 src文件夹: 代码文件夹 |----assets文件夹: 存储项目中自己的一些静态文件(图片/字体等) |----components文件夹: 存储项目中的自定义组件(小组件,公共组件) |----views文件夹: 存储项目中的自定义组件(大组件,页面级组件,路由级别组件) |----router文件夹: 存储VueRouter相关文件 |----store文件夹: 存储Vuex相关文件 |----App.vue:根组件 |----main.js:入口js文件