在创建一个vue对象的时候回有许许多多的步骤,这时,在每个步骤执行完后需要有回调函数来确定这一步执行完毕后需要做什么事情,比如网络请求。生命周期函数就应运而生。
vue生命周期如下:
实例组件刚创建,元素DOM和数据都还没有初始化,暂时不知道能在这个周期里面进行生命操作。
数据data已经初始化完成,方法也已经可以调用,但是DOM未渲染。有人问了,请求都是异步的,并不会阻碍实例加载。这是我个人水平的问题,这边改正,在这个周期里面,请求因为是异步的,不会阻碍实例加载,除非是那些同步操走才会导致页面空白。这样说来,在这个周期里面进行请求,渲染速度反而会更快。
DOM未完成挂载,数据也初始化完成,但是数据的双向绑定还是显示{{}},这是因为Vue采用了Virtual DOM(虚拟Dom)技术。先占住了一个坑。
数据和DOM都完成挂载,在上一个周期占位的数据把值给渲染进去。可以在这边请求,不过created请求会更好一些。这个周期适合执行初始化需要操作DOM的方法。
只要是页面数据改变了都会触发,数据更新之前,页面数据还是原来的数据,当你请求赋值一个数据的时候会执行这个周期,如果没有数据改变不执行。
只要是页面数据改变了都会触发,数据更新完毕,页面的数据是更新完成的。beforeUpdate和updated要谨慎使用,因为页面更新数据的时候都会触发,在这里操作数据很影响性能和容易死循环。
这个周期是在组件销毁之前执行,在我项目开发中,觉得这个其实有点类似路由钩子beforeRouterLeave,都是在路由离开的时候执行,只不过beforeDestroy无法阻止路由跳转,但是可以做一些路由离开的时候操作,因为这个周期里面还可以使用data和method。比如一个倒计时组件,如果在路由跳转的时候没有清除,这个定时器还是在的,这时候就可以在这个里面清除计时器。
说实在的,我还真的不知道这个周期跟beforeDestroy有什么区别,我在这个周期里面调用data的数据和methods的方法都能调用,所以我会觉得跟beforeDestroy是一样的。
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>hello world</title> <script src="./lib/vue.js"></script> </head> <body> <div id="app"> <p>{{ msg }}</p> </div> <script type="text/javascript"> //创建一个vue实例 //这就是我们的vm调度者 var vm = new Vue({ //使用id选择器选择需要绑定的元素 el: '#app', //数据层,这就是需要绑定到界面的数据 data: { msg: 'hello world' }, //方法区,存储需要绑定到界面的方法 method: { }, created:function:(){ //此处可以进行网络请求,从后台拿取数据更新msg } }) </script> </body> </html>
插值表达式数据与视图双向绑定,视图会随数据的变化而变化,4种插值表达式如下:
<p>{{ msg }}</p> <p>{{ msg.length }}</p> <p>{{msg + '拼接的字符串'}}</p> <p>{{dlag ? '条件为真' : '条件为假'}}</p>
var vm = new Vue({ //使用id选择器选择需要绑定的元素 el: '#app', //数据层,这就是需要绑定到界面的数据 data: { msg: 'hello world' }, })
结果:
代表只渲染一次,之后不会随着数据的改变而改变。
<div id="app"> <p v-once>{{ msg }}</p> </div>
data中的数据如果存在标签,就需要v-html。
<div id="app"> <p v-html> {{url}} </p> </div>
var vm = new Vue({ //使用id选择器选择需要绑定的元素 el: '#app', //数据层,这就是需要绑定到界面的数据 data: { url: '<h3>v-html</h3>' } })
有时候就不需要插值表达式,直接输出{{message}}的内容就需要使用到v-pre属性。
<div id="app"> <p v-pre>{{ msg }}</p> </div>
有时候网页渲染过慢,会显示{{msg}}而非数值。这时就要v-cloak属性。
<style> [cloak]{ display:null; } </style> <div id="app" v-cloak> <p v-pre>{{ msg }}</p> </div>
有时候我们可能需要在{{}}里进行一些计算在展示出来数据,vue给我们提供了一个特别好的解决方案:计算属性,我们可以把这些计算的过程写到一个计算属性中去,然后让它动态的计算就可以了。
<div id="app"> <p>{{ fullName }}</p> </div>
var vm = new Vue({ el: '#app', data: { firstName: 'tang', secondtName: 'dexuan' }, computed: { fullName:function(){ return firstName+' '+secondtName } } })
计算属性中是有缓存的,不是每次调用都计算一遍。
有时候我们需要将vue option中data数据绑定到html某个标签的属性上,就可以使用v-bind指令,v-bind的语法糖是:
<div id="app"> <img v-bind:src="url" /> </div>
等价于
<div id="app"> <img :src="url" /> </div>
var vm = new Vue({ el: '#app', data: { url: 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1580928601481&di=3f39275cf8d21264208b21a5b9de7b3c&imgtype=0&src=http%3A%2F%2Fsc.sinaimg.cn%2Fiframe%2F453%2F2012%2F0509%2FU3759P841T453D1F12086DT20140727103938.jpg', } })
这就代表了src属性绑定了url。
<div id="app"> <button v-on:click="cliEvent">我是按钮</button> <button @click="cliEvent">我是按钮</button> </div>
var vm = new Vue({ //使用id选择器选择需要绑定的元素 el: '#app', //数据层,这就是需要绑定到界面的数据 data: { msg: 'hello world' }, //方法区,存储需要绑定到界面的方法 method: { cliEvent(){ alter("ok") } } })
在事件中,vue会默认给你个event参数,event可以获取当前状态信息。
var vm = new Vue({ //使用id选择器选择需要绑定的元素 el: '#app', //数据层,这就是需要绑定到界面的数据 data: { msg: 'hello world' }, //方法区,存储需要绑定到界面的方法 method: { cliEvent(event){ alter(event) } } })
一般用于表单控件,比如文本框,实现数据和value的绑定
例子:
<div id="app"> <input type="text" v-model="myText"> </div>
var vm = new Vue({ //使用id选择器选择需要绑定的元素 el: '#app', //数据层,这就是需要绑定到界面的数据 data: { myText: 'hello world' } })
用于控制相关组件是否显示
<div id="app"> <input type="text" v-if="is_show"> </div>
var vm = new Vue({ //使用id选择器选择需要绑定的元素 el: '#app', //数据层,这就是需要绑定到界面的数据 data: { is_show: true } })
用于控制相关组件是否显示,如果is_show为true显示第一个,else显示第二个
<div id="app"> <input type="text" v-if="is_show"> <input type="text" v-else> </div>
var vm = new Vue({ //使用id选择器选择需要绑定的元素 el: '#app', //数据层,这就是需要绑定到界面的数据 data: { is_show: true } })
实现本质⽅法不同,v-show本质就是通过控制css中的display设置为none,控制隐藏,只会编译⼀次;v-if是动态的向DOM树内添加或者删除DOM元素,若初始值为false,就不会编译了。⽽且v-if不停的销毁和创建⽐较消耗性能。
在data中定义普通数组
data:{ list:[1,2,3,4,5,6] }
在html中使用 v-for 指令渲染
<p v-for="(item,i) in list">--索引值--{{i}} --每一项--{{item}}</p>
在data中定义对象数组
data:{ list:[1,2,3,4,5,6], listObj:[ {id:1, name:'zs1'}, {id:2, name:'zs2'}, {id:3, name:'zs3'}, {id:4, name:'zs4'}, {id:5, name:'zs5'}, {id:6, name:'zs6'}, ] }
在html中使用 v-for 指令渲染
<p v-for="(user,i) in listObj">--id--{{user.id}} --姓名--{{user.name}}</p>
在data中定义对象
data:{ user:{ id:1, name:'托尼.贾', gender:'男' } }
在html中使用 v-for 指令渲染
<p v-for="(val,key) in user">--键是--{{key}}--值是--{{val}}</p>
<!-- 注意:如果使用v-for迭代数字的话,前面 count 的值从 1 开始--> <p v-for="count in 10">这是第{{count}}次循环</p>
将一个问题拆分成多个可以处理的小问题,再将其放入整体,这就是组件化思想。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> </head> <body> <div id="app"> <my-cpn></my-cpn> <my-cpn></my-cpn> </div> </body> <script> const my_cpn = Vue.extend({ template: '<p>这是我的组件</p>' }) // 定义名为 todo-item 的新组件 Vue.component('my-cpn', my_cpn) var app = new Vue({ el: "#app", data: { m: "hello vue.js", }, }); </script> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> </head> <body> <div id="app"> <my-cpn></my-cpn> <my-cpn></my-cpn> </div> </body> <script> const my_cpn = Vue.extend({ template: '<p>这是我的组件</p>' }) var app = new Vue({ el: "#app", data: { m: "hello vue.js", }, components: { myCpn: my_cpn } }); </script> </html>
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>vue code</title> <script src="./lib/vue.js"></script> </head> <body> <div id="app"> <cpn2></cpn2> <cpn1></cpn1> </div> </body> <script type="text/javascript"> //创建子组件 var com1 = Vue.extend({ template: "<h3>来了老弟</h3>" }) //创建父组件 var com2 = Vue.extend({ template: ` <div> <h2>来了老哥</h2> <cpn1></cpn1> </div> `, components:{ cpn1:com1 } }) //语法糖模式注册 //注册组件 var vm = new Vue({ el: '#app', data: { msg: "单纯的我" }, methods: {}, components:{ cpn2:com2, cpn1:{ template: "<h3>来了老弟2</h3>" } } }) </script> </html>
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>vue code</title> <script src="./lib/vue.js"></script> </head> <body> <div id="app"> <cpn2></cpn2> <cpn1></cpn1> </div> <template id="cpn"> <div> <h1>来了老弟</h1> <p>内容。。。。。。</p> </div> </template> </body> <script type="text/javascript"> //注册组件 var vm = new Vue({ el: '#app', data: { msg: "单纯的我" }, methods: {}, components:{ cpn2:{ template:"#cpn" } } }) </script> </html>
以下是使用组件封装一个计数器
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>vue code</title> <script src="./lib/vue.js"></script> </head> <body> <div id="app"> <cpn></cpn> <cpn></cpn> </div> <template id="cpn"> <div> <h1>计数器:{{counter}}</h1> <button @click="increase">+</button> <button @click="decrease">-</button> </div> </template> </body> <script type="text/javascript"> //注册组件 var vm = new Vue({ el: '#app', data: { msg: "单纯的我" }, methods: {}, components:{ cpn:{ template:"#cpn", data(){ return{ counter:0 } }, methods:{ increase:function(){ this.counter++ }, decrease:function(){ this.counter-- } } } } }) </script> </html>
最终结果:
思考,为什么data要做成一个函数呢?因为组件中的数据必须相互独立,return一个对象就会开辟一个新的堆空间,这样可以使得数据隔离