1.生命周期
表示的是一个vue实例对象的一个轮回。
人的生命周期。一个月内要办理出生证明以及去派出所办户口、打疫苗
从技术上来考虑,这8个生命周期就是8个函数,也叫生命周期钩子函数 。不需要自己手动调用,它是在相应的时机上自动触发的,语法上这8个函数不在methods中。
-
beforeCreate 创建之前
-
created 创建完成 : 最早发送ajax的地址在这里
-
beforeMount 挂载之前
-
mounted 挂载完成 : 有些项目中,一些开发者也在这里发送ajax。 绑定window事件scroll/ 获取页面的高 / 开启定时器
-
beforeUpdate 更新之前
-
updated 更新完成
-
beforeDestroy 销毁之前 解除window事件scroll/关闭启定时器
-
destroyed 销毁完成
<body> <div id="app"> {{username}} <h2>我是h2</h2> <button @click="username='ls'">更改username</button> <button @click="kill">销毁实例</button> </div> </body> <script src="vue.js"></script> <script> new Vue({ el: '#app', data: { username:'zs' }, methods: { kill(){ this.$destroy() //console.log( this ); } }, //$el指的是 #app元素整体 //$data 初始化的数据 //vue实例创建之前 beforeCreate(){ //console.log( this ); console.group('-----beforeCreate------------') console.log( this.$el,'----this.$el----' ) //undefined console.log( this.$data,'----this.data----' ) //undefined console.groupEnd() }, //vue实例创建完成 : 最早发送ajax的地址在这里 created(){ console.group('-----created------------') console.log( this.$el,'----this.$el----' ) //undefined console.log( this.$data,'----this.data----' ) //存在 :最早能访问数据的地方 console.groupEnd() }, //数据挂载之前 , 挂载(指的是把data中的数据渲染在页面上) beforeMount(){ console.group('-----beforeMount------------') console.log( this.$el,'----this.$el----' ) //存在:还没有解析数据呢 console.log( this.$data,'----this.data----' ) //存在 console.groupEnd() }, //数据挂载完成 : 绑定window事件scroll/ 获取页面的高 / 开启定时器 mounted(){ console.group('-----mounted------------') console.log( this.$el,'----this.$el----' ) //存在:解析模板成功,数据也挂载了 console.log( this.$data,'----this.data----' ) //存在 console.groupEnd() }, //视图更新之前: 数据已经是最新的 beforeUpdate(){ console.group('-----beforeUpdate------------') console.log( this.$el,'----this.$el----' ) // console.log( this.$data,'----this.data----' ) //存在 console.groupEnd() }, //视图更新完成: 数据已经是最新的 updated(){ console.group('-----updated------------') console.log( this.$el,'----this.$el----' ) // console.log( this.$data,'----this.data----' ) //存在 console.groupEnd() }, //vue实例销毁之前 : 解决window事件scroll/关闭启定时器 beforeDestroy(){ console.group('-----beforeDestroy------------') console.log( this.$el,'----this.$el----' ) // console.log( this.$data,'----this.data----' ) //存在 console.groupEnd() }, destroyed(){ console.group('-----destroyed------------') console.log( this.$el,'----this.$el----' ) // console.log( this.$data,'----this.data----' ) //存在 console.groupEnd() } }) </script>
2.侦听器watch
2.1 定义
侦听器又名监听器 侦听器是属于vue中一个特殊的对象,对象上都是方法,和el、data平级,用来监听data数据的改变,从而做出及时的响应. 应用: 百度搜索 百度翻译 淘宝搜索...
2.2-1 普通监听
* 普通监听: 除对象以下的数据(数组) * 监听器中方法名是其data中对应的属性名 * 系统自动注入的参数,有两个 newVal: 更新后的新值 oldVal:更新前的旧值 * 监听器中的所有方法:无需调用,当被监听的数据发生改变时,自动被执行
2.2-2 深度监听
对象数据的监听需要使用深度监听,虽然也可以兼听普通数据但是没有必要使用尝试监听 * 深度监听需要使用固定方法handler和deep属性 * 系统自动注入一个参数: newVal,在深度监听中无法获取更新之前的旧值,因为使用深度监听中没有保存更新之前的旧值,这也和引用类型特点有关系
<body> <div id="app"> <h2>1. 普通兼听</h2> <input type="text" placeholder="用户名" v-model="username"> <input type="text" placeholder="年龄" v-model="age"><hr> <input type="text" v-model="arr[1]"> <hr> <h2>深度兼听-对象</h2> <input type="text" v-model="person.username"> </div> </body> <script src="vue.js"></script> <script> new Vue({ el: '#app', data: { username:'', age:'', arr:[ 11,22,33 ], person:{ username:'zs', age:20 } }, methods: { }, watch:{ //一个一个的兼听器。需要定义函数,函数名就是你要兼听数据的名称 //1. 普通兼听 username( newValue,oldValue ){ //第1个参数是新值,第2个旧值 // console.log( 'username变化 了' ); //当数据变化 了,要做的事情就写在此兼听器中。 // console.log( this.username ); console.log( newValue,oldValue ); }, age(newValue,oldValue){ // console.log( 'age变化 了' ); console.log( newValue,oldValue ); }, //兼听数组也可以使用普通兼听 arr( newValue,oldValue ){ //数组是引用类型,新值和旧值是一致的 console.log( newValue,oldValue ); }, //对象使用普通兼听-兼听不到 // person(){ // console.log( '12345' ); // }, //2. 深度兼听-兼听对象 person:{ deep:true,//true深度兼听,默认为false普通兼听 handler( newValue,oldValue ){ //对象是引用类型,新值和旧值是一致的 // console.log( 'person变化 了' ); console.log( newValue,oldValue ); } } } }) </script>
2.3 百度搜索
jsonp跨域 步骤: 1.创建script标签 2.为script标签增加src属性,并且是不是要传递一个cb或callback的参数给后端 3.将script追加到文档中,才会发请求 4.返回的格式是jsonp的格式: 函数名( {} ) 百度建议搜索的接口地址 https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=web&cb=fn
<body> <div id="app"> <!-- 使用到的知识点: 1. watch 2. 请求百度的数据 cors/jsonp 3. 回忆jsonp原理 3.1 创建;script 标签 3.2 script的src去请求一个jsonp的地址 并且是不是要传递一个cb或callback的参数给后端 3.3 把script放在页面中才会真正的去请求 3.4 返回jsonp格式 函数名( json数据 ) https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=web&cb=fn --> <input type="text" placeholder="输入搜索关键字" v-model="keyword"> <ul> <li v-for="item in suggests">{{item}}</li> </ul> </div> </body> <script src="vue.js"></script> <script> let vm = new Vue({ el: '#app', data: { keyword:'', suggests:[] }, methods: { }, watch:{ keyword(newValue,oldValue){ //['web','web开发','web前端'] //1. ;keyword,发送请求 // this.suggests = ['web','web开发','web前端'] if( !newValue ){ //如果未输入关键字,则无需发送请求 this.suggests = [] return } let oScript = document.createElement('script') oScript.src = `https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=${newValue}&cb=fn` document.body.appendChild( oScript ) } } }) function fn( res ){ console.log( res.s,'结果') //res.s 才是建议搜索列表 vm.suggests = res.s } </script>
3.计算属性
computed
3.1 作用
1. 使用计算属性可以处理一些复杂的特殊的业务逻辑 2. 一行代码无法实现的逻辑时,需要使用计算属性 特点:可能需要很变量数据,最后计算出一个结果
购物车(总价格、数量、是否全选)、学生的总成绩、评分
3.2 使用
* 方法名自定义 * 在计算属性方法中必须要有return * return的结果被其方法名所接受 * data中的属性名不能和computed中的方法名相同
<body> <div id="app"> <input type="text" v-model="lastname"> <input type="text" v-model="firstname"> {{getFullName}} </div> </body> <script src="vue.js"></script> <script> new Vue({ el: '#app', data: { lastname:'james', firstname:'lebron', a:'my is a' }, computed:{ // 计算属性中依赖的变量发生改变,则计算属性的值自动变化 getFullName(){ return (this.firstname + ' ' + this.lastname).toUpperCase() }, // a(){ //* data中的属性名不能和computed中的方法名相同 // } } }) </script>
3.3 计算属性和methods的区别
* 区别: 1.computed中方法名直接书写, methods方法名需要调用 2.computed中有缓存数据,在计算属性中他的数据依赖于data数据,无论被调用了几次, 始终都会显示第一次调用的结果.只有当data中的数据发生改变时,才会被再次执行.优势:提高运行效率 3.methods中的方法,调用几次就执行几次. * 相同: 1.执行结果都一样 2.都是采用function进行声明 * 应用场景: 1.处理一些复杂的业务逻辑时,需要产生结果时,使用计算属性 2.一般用来处理事件函数时,使用methods
new Vue({ el: '#app', data: { lastname:'james', firstname:'lebron', a:'my is a' }, methods:{ getFullName2(){ //console.log( '----getFullName2-----' ); return (this.firstname + ' ' + this.lastname).toUpperCase() } }, computed:{ // 计算属性中依赖的变量发生改变,则计算属性的值自动变化 getFullName(){ console.log( '----getFullName-----' );//计算属性有缓存的作用 return (this.firstname + ' ' + this.lastname).toUpperCase() }, // a(){ //* data中的属性名不能和computed中的方法名相同 // } } })
3.4 计算属性的get和set方法:完整写法(了解)
<body> <div id="app"> <input type="text" v-model="code"> <hr> {{ getCode }} </div> </body> <script src="vue.js"></script> <script> new Vue({ el: '#app', data: { code:'abc' }, computed:{ //把code变为大写,还倒序 getCode:{ get(){ return this.code.toUpperCase().split('') .reverse().join('') }, set(val){ //不是改变getCode值,而是改变getCode中某个依赖值 this.code = val } }, // } }) </script>
一些优化
1.一般情况下不要将v-for和v-if一起使用, 因为v-for的优先级高于v-if:指的是不要放在一个标签上 2.使用无意义标签包裹div template(模板标签,不会被浏览器所解析) 3. v-cloak 指令:优化我们的闪屏
<style> [v-cloak]{ display: none; } /* [id='btn']{ background-color: red; } */ /* [id]{ background-color: red; } */ /* .aa{ } #aaa{ } */ </style> <body> <div id="app" v-cloak> <button id="btn">asdf</button> <button id="btn1">asdf</button> <table border="1" style="border-collapse: collapse;" width="300"> <tr> <th>id</th> <th>姓名</th> <th>数学</th> </tr> <!-- 1.一般情况下不要将v-for和v-if一起使用, 因为v-for的优先级高于v-if:指的是不要放在一个标签上 2.使用无意义标签包裹div template(模板标签,不会被浏览器所解析) --> <template v-if="filterStudents.length > 0"> <tr v-for="(item,index) in filterStudents" :key="item.id"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.shuxue}}</td> </tr> </template> <tr v-else> <td colspan="3">暂无数据</td> </tr> <tr> <td colspan="3">数学总成绩:{{getTotalShuXue}},数学平均成绩,{{getAvgShuXue}} 最高分:{{getMaxShuXue}}</td> </tr> </table> </div> </body> <script src="vue.js"></script> <script> new Vue({ el: '#app', data: { students:[ { id:'001',name:'zs',shuxue:88 }, { id:'003',name:'ls',shuxue:78 }, { id:'006',name:'ww',shuxue:69 }, { id:'009',name:'ql',shuxue:88 }, ] }, computed: { filterStudents(){ return this.students.filter( (item)=>{ return item.shuxue > 90 } ) }, getTotalShuXue(){ let t = 0 //存放总成绩的变量: 累加 this.students.forEach( item=>{ t += item.shuxue } ) return t }, getAvgShuXue(){ let t = 0 //存放总成绩的变量: 累加 this.students.forEach( item=>{ t += item.shuxue } ) return t/this.students.length }, getMaxShuXue(){ let stus = [...this.students] //需要拷贝 一份,否则影响原数据 。 // stus.sort( (stu1,stu2)=>{ // return stu2.shuxue - stu1.shuxue // } ) stus.sort( (stu1,stu2)=>stu2.shuxue - stu1.shuxue ) return stus[0].shuxue } } }) </script>
3.5 购物车案例
4.过滤器
处理数据,把数据整理成符合要求的格式。字符串|数值
4.1 局部过滤器
1.方法名自定义 2.系统自动传递形参:e 3.过滤器方法中必须有return,return的结果被其方法名所接受 应用场景 : 格式化时间、价格保留小数等
<body> <div id="app"> <!-- | 管道符 --> {{ 'hello' | word2FirstUpperCase }} <hr> {{ 'world' | word2FirstUpperCase }} <hr> <!-- 过滤器传参 --> {{ 'hello' | word2FirstUpperCase2(1) }} <hr> {{ 'world' | word2FirstUpperCase2(2) }} </div> </body> <script src="vue.js"></script> <script> new Vue({ el: '#app', data: { }, //过滤器:本质上还是函数 filters:{ // 英文单词首字母大写 word2FirstUpperCase( e ){ //必须有return返回值 //console.log( e,'在你哪个数据后面使用了过滤器就会自动传递过来当前数据' ); return e.substring(0,1).toUpperCase() + e.substring(1) }, // word2FirstUpperCase2( e,num ){ //必须有return返回值 //console.log( e,'在你哪个数据后面使用了过滤器就会自动传递过来当前数据' ); console.log( num ); return e.substring(0,num).toUpperCase() + e.substring(num) } } }) </script>
4.2 全局过滤器
<body> <div id="app"> {{ 20 | priceToFixed }} <hr> {{ 20 | priceToFixed(2) }} </div> </body> <script src="vue.js"></script> <script> //在实例化之前注册全局过滤器. Vue.filter( 名称,函数 ) 注册过滤器 Vue.filter( 'priceToFixed',(e,num = 2)=>{ console.log(e); //如果不传num默认为2 return e.toFixed(num) } ) new Vue({ el: '#app', data: { }, methods: { } }) </script>
4.3全局过滤器和局部过滤器的区别
全局过滤器:在任何vue实例上都可以使用 局部过滤:只在当前vue实例上使用 实际应用: 项目中:对某一个数据频繁使用,并且是要实现过滤时,使用全局过滤器即可 对一写数据只在某几个功能中使用,建议使用局部过滤器.
<body> <div id="app"> {{ 20 | priceToFixed }} <hr> {{ 20 | priceToFixed(2) }} <hr> <h2>首字母大写</h2> {{'aabc'|word2FirstUpperCase2}} </div> <hr> <div id="root1"> <h2>root</h2> {{ 20 | priceToFixed(2) }} <hr> {{'aabc'|word2FirstUpperCase2}} </div> </body> <script src="vue.js"></script> <script> //在实例化之前注册全局过滤器. Vue.filter( 名称,函数 ) 注册过滤器 Vue.filter('priceToFixed', (e, num = 2) => { console.log(e); //如果不传num默认为2 return e.toFixed(num) }) new Vue({ el: '#app', data: { }, filters: { word2FirstUpperCase2(e, num=1) { //必须有return返回值 //console.log( e,'在你哪个数据后面使用了过滤器就会自动传递过来当前数据' ); console.log(num); return e.substring(0, num).toUpperCase() + e.substring(num) } } }) new Vue({ el:'#root1' }) </script>
4.4 封装时间过滤器
Vue.filter('formateTime', (e, type = 'yyyy-mm-dd h:m:s') => {
let t = new Date(e)
let year = t.getFullYear()
let month = t.getMonth() + 1 + ''
month = month.padStart(2, 0)
let day = t.getDate() + ''
day = day.padStart(2, 0)
let h = t.getHours() + ''
h = h.padStart(2, 0)
let m = t.getMinutes() + ''
m = m.padStart(2, 0)
let s = t.getSeconds() + ''
s = s.padStart(2, 0)
if (type == 'yyyy-mm-dd h:m:s') {
return `${year}-${month}-${day} ${h}:${m}:${s}`
} else if (type == 'yyyy-mm-dd') {
return `${year}-${month}-${day}`
} else if (type == 'h:m:s') {
return `${h}:${m}:${s}`
} else {
return `${year}/${month}/${day}`
}
})