- 构造选项回顾
- 进阶属性
- watch侦听
-曾老湿, 江湖人称曾老大。
-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。
构造选项回顾
Vue的构造选项 |
---|
每一类属性中都会有很多属性:
数据: - data - props - propsData - computed - methods - watch
DOM - el - template - render - renderError
生命周期钩子 - beforeCreate - created - beforeMount - mounted - beforeUpdate - updated - activated - deactivated - beforeDestroy - destroyed - errorCaptured
资源 - directives - filters - components
组合 - parent - mixins - extends - provide - inject
属性分阶段:
红色属性:好学,必学,几句话就能说明白 黄色属性:高级属性,费点劲,需要单独课程讲解 蓝色属性:不常用,可学,可不学 橙色属性:很不常用,用的时候自己看下文档即可 粉色属性:比较特殊,重点讲解一下
之前我们已经把入门属性都讲完了。
代码语言:javascript复制#el挂载点
可以用$mount代替
#data内部数据
支持对象和函数,优先使用函数
#methods方法
事件处理函数或者是普通函数
#components
Vue组件,注意大小写
三种引入方式,推荐最后一种
#四个钩子
created,实例出现在内存中
mounted,实例出现在页面中
updated,实例更新了
destroyed,实例从页面和内存中消亡了
#props外部数据
也叫属性
message="n"传入字符串
:message="n"传入this.n数据
:fn="add"传入this.add函数
进阶属性
代码语言:javascript复制#computed计算属性
不需要加括号
它会根据依赖是否变化来缓存
#watch侦听
一旦data发生变化,就执行的函数
options.watch用法
this.$watch用法
deep,immediate含义
#directives
内置指令v-if/v-for/v-bind/v-on
自定义指令例如:v-focus
指令是为了减少重复的DOM操作
#mixin混入
重复三次之后的出路
混入VS全局混入
选项自动合并
混入就是为了减少重复的构造选项
#extends继承
先了解一下Vue.extend
你觉得用了mixin还是重复
于是你自己写了一个View,它继承Vue
你还可以预先定义其他构造选项
继承就是为了减少重复的构造选项
那为什么不用ES6的extends呢?
#provides/inject
爷爷想和孙子讲话怎么办?
祖宗想跟它的所有后代讲话怎么办?
答案是全局变量,但是全局变量太low
所以我们需要局部的全局变量
讲之前,我们先回顾一下响应式原理
options.data 会被Vue监听 会被Vue实例代理 每次对data的读写都会被Vue监控 Vue会在data变化时更新UI
这节课讲 data变化时除了更新UI,还能做点啥?
computed计算属性 |
---|
用途 倍计算出来的属性,就是计算属性 例1:用户名展示
代码语言:javascript复制import Vue from "vue/dist/vue.js"
Vue.config.productionTip = false
new Vue({
data:{
user:{
email:"133411023@qq.com",
nickname:"曾老湿",
phone:"13123456789"
}
},
//不如用computed来计算displayName
template:`
<div>
{{user.nickname || user.email || user.phone}}
</div>
`
}).$mount("#app")

目前我们代码只有一个地方需要展示用户名,但是如果说,后面还有地方使用用户名,我们还得写一遍{{user.nickname || user.email || user.phone}}
,如果有1万个地方都需要用到这个显示,我们要写1万遍?然后突然...老板娘说,需求改了,我们优先显示手机,然后再显示邮件{{user.nickname || user.phone || user.email}}
刺激不?你是不是要改1万遍?万一哪个地方漏改或者少加一个空格那就是代码中的bug,老板娘就是要让你爽...
所以我们写代码的时候,需要遵循一个DRY
原则 Don't Repeat Yourself
不要重复你自己。
emm...那么,这个时候,我们需要使用计算属性
代码语言:javascript复制import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
data: {
user: {
email: "133411023@qq.com",
nickname: "曾老湿",
phone: "13123456789"
}
},
computed:{
displayName(){
const user = this.user
return user.nickname || user.email || user.phone
}
},
//不如用computed来计算displayName
template: `
<div>
{{displayName}}
</div>
`
}).$mount("#app");

使用getter和setter
代码语言:javascript复制import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
data: {
user: {
email: "133411023@qq.com",
nickname: "曾老湿",
phone: "13123456789"
}
},
computed:{
displayName:{
get(){
const user = this.user
return user.nickname || user.email || user.phone
},
set(value){
this.user.nickname = value
}
}
},
//不如用computed来计算displayName
template: `
<div>
{{displayName}}
<button @click="updateName">set</button>
</div>
`,
methods:{
updateName(){
this.displayName = "苍老师"
}
}
}).$mount("#app");

例2:列表展示
代码语言:javascript复制import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
let id = 0;
const createUser = (name, gender) => {
id = 1;
return { id, name, gender };
};
new Vue({
data() {
return {
users: [
createUser("曾老湿", "男"),
createUser("苍老师", "女"),
createUser("武藤兰", "女"),
createUser("饭岛爱", "女")
]
};
},
//如何给三个按钮加事件处理函数
//思路一:点击之后改users
//思路二:使用computed
template: `
<div>
<div>
<button>全部</button>
<button>男</button>
<button>女</button>
</div>
<ul>
<li v-for="u in users" :key="u.id">
{{u.name}} - {{u.gender}}
</ul>
</div>
`
}).$mount("#app");
不使用计算属性,代码如下:
代码语言:javascript复制import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
let id = 0;
const createUser = (name, gender) => {
id = 1;
return { id, name, gender };
};
new Vue({
data() {
return {
users: [
createUser("曾老湿", "男"),
createUser("苍老师", "女"),
createUser("武藤兰", "女"),
createUser("饭岛爱", "女")
],
displayUsers: []
};
},
created(){
this.displayUsers = this.users
},
methods:{
showMale(){
this.displayUsers = this.users.filter(u => u.gender === '男');
},
showFemale(){
this.displayUsers = this.users.filter(u => u.gender === '女');
},
showAll(){
this.displayUsers = this.users;
}
},
template: `
<div>
<div>
<button @click="showAll">全部</button>
<button @click="showMale">男</button>
<button @click="showFemale">女</button>
</div>
<ul>
<li v-for="(u,index) in displayUsers" :key="index">
{{u.name}} - {{u.gender}}
</ul>
</div>
`
}).$mount("#app");
使用计算属性
代码语言:javascript复制import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
let id = 0;
const createUser = (name, gender) => {
id = 1;
return { id, name, gender };
};
new Vue({
data() {
return {
users: [
createUser("曾老湿", "男"),
createUser("苍老师", "女"),
createUser("武藤兰", "女"),
createUser("饭岛爱", "女")
],
gender: ''
};
},
computed:{
displayUsers(){
const {users,gender} = this
if(gender === ''){
return users
}else if(gender === 'male'){
return users.filter(u => u.gender === '男')
}else if(gender === 'female'){
return users.filter(u => u.gender === '女')
}
}
},
methods:{
showMale(){
this.gender = 'male'
},
showFemale(){
this.gender = 'female'
},
showAll(){
this.gender = ''
},
},
template: `
<div>
<div>
<button @click="showAll">全部</button>
<button @click="showMale">男</button>
<button @click="showFemale">女</button>
</div>
<ul>
<li v-for="(u,index) in displayUsers" :key="index">
{{u.name}} - {{u.gender}}
</ul>
</div>
`
}).$mount("#app");
使用计算属性,高端写法
代码语言:javascript复制import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
let id = 0;
const createUser = (name, gender) => {
id = 1;
return { id, name, gender };
};
new Vue({
data() {
return {
users: [
createUser("曾老湿", "男"),
createUser("苍老师", "女"),
createUser("武藤兰", "女"),
createUser("饭岛爱", "女")
],
gender: ''
};
},
computed:{
displayUsers(){
const {users,gender} = this
if(gender === ''){
return users
}else if(gender === 'male'){
return users.filter(u => u.gender === '男')
}else if(gender === 'female'){
return users.filter(u => u.gender === '女')
}
}
},
template: `
<div>
<div>
<button @click="gender = ''">全部</button>
<button @click="gender = 'male'">男</button>
<button @click="gender = 'female'">女</button>
</div>
<ul>
<li v-for="(u,index) in displayUsers" :key="index">
{{u.name}} - {{u.gender}}
</ul>
</div>
`
}).$mount("#app");
使用计算属性,更高端写法
代码语言:javascript复制import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
let id = 0;
const createUser = (name, gender) => {
id = 1;
return { id, name, gender };
};
new Vue({
data() {
return {
users: [
createUser("曾老湿", "男"),
createUser("苍老师", "女"),
createUser("武藤兰", "女"),
createUser("饭岛爱", "女")
],
gender: ''
};
},
computed:{
displayUsers(){
const hash = {
male:'男',
female:'女'
}
const {users,gender} = this;
if(gender === ''){
return users
}else if(typeof gender === 'string'){
return users.filter(u => u.gender === hash[gender])
}else{
throw new Error("gender 的值是意外的值")
}
}
},
template: `
<div>
<div>
<button @click="gender = ''">全部</button>
<button @click="gender = 'male'">男</button>
<button @click="gender = 'female'">女</button>
</div>
<ul>
<li v-for="(u,index) in displayUsers" :key="index">
{{u.name}} - {{u.gender}}
</ul>
</div>
`
}).$mount("#app");
缓存 如果依赖的属性没有变化,就不会重新计算 getter/setter默认不会做缓存,Vue做了特殊处理
watch侦听
案例1:撤销 |
---|
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
data:{
n:0,
history:[],
inUndomode:false
},
watch: {
n(newValue,oldValue){
if(!this.inUndomode)
this.history.push({from:oldValue,to: newValue})
}
},
template: `
<div>
{{n}}
<hr/>
<button @click="add1"> 1</button>
<button @click="add2"> 2</button>
<button @click="minus1">-1</button>
<button @click="minus2">-2</button>
<hr/>
<button @click="undo">撤销</button>
<hr/>
{{history}}
</div>
`,
methods:{
add1(){
this.n =1
},
add2(){
this.n =2
},
minus1(){
this.n -=1
},
minus2(){
this.n -=2
},
undo(){
const last = this.history.pop();
this.inUndomode = true
// console.log("ha" this.inUndomode)
const old = last.from
this.n = old // watch n的函数会异步调用
this.$nextTick(()=>{
this.inUndomode = false
})
}
}
}).$mount('#app')
案例2:模拟computed |
---|
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
data:{
user:{
email:"zls@qq.com",
nickname:"曾老湿",
phone:"1334567890"
},
displayName: ""
},
watch: {
'user.email':{
handler(){
const {user:{email,nickname,phone}} = this
this.displayName = nickname || email || phone
},
immediate: true // watch的第一次是不监听的,从0到有不算是变化,所以使用immediate第一次也运行
},
'user.phone':{
handler(){
const {user:{email,nickname,phone}} = this
this.displayName = nickname || email || phone
},
immediate:true
},
'user.nickname':{
handler(){
const {user:{email,nickname,phone}} = this
this.displayName = nickname || email || phone
},
immediate:true
}
},
template: `
<div>
{{displayName}}
<button @click="user.nickname=undefined">remove nickname</button>
</div>
`,
methods:{
changed(){
console.log(arguments)
const user = this.user
this.displayName = user.nickname || user.email || user.phone
}
}
}).$mount('#app')
说实话,这样做很傻...
watch的deep属性 |
---|
import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
data:{
n:0,
obj:{
a:'a',
b:'b'
}
},
template: `
<div>
<button @click="n = 1">n 1</button>
<button @click="obj.a = 'hi'">obj.a 'hi'</button>
<button @click="obj = {a:'a',b:'b'}">obj = 新对象</button>
</div>
`,
watch: {
n(){
console.log('n 变了')
},
obj() {
console.log('obj 变了')
},
"obj.a":function(){
console.log('obj.a 变了')
},
"obj.b":function(){
console.log("obj.b 变了")
}
},
}).$mount('#app')
按理来说,如果是obj.a变了我们就认为obj变了。但是当我们点击obj.a hi的时候,结果只有obj.a变了,obj并没有变化,因为还是存储的原来的内存地址。所以在Vue中,想看看obj里面的内容有没有变化,需要使用deep
属性。

deep属性代码如下:首先将obj变成一个对象
代码语言:javascript复制import Vue from "vue/dist/vue.js";
Vue.config.productionTip = false;
new Vue({
data:{
n:0,
obj:{
a:'a',
b:'b'
}
},
template: `
<div>
<button @click="n = 1">n 1</button>
<button @click="obj.a = 'hi'">obj.a 'hi'</button>
<button @click="obj = {a:'a',b:'b'}">obj = 新对象</button>
</div>
`,
watch: {
n(){
console.log('n 变了')
},
obj: {
handler(){
console.log('obj 变了')
},
deep:true
},
}
}).$mount('#app')
同样点击obj.a hi,就会出现obj变了,就不需要再监听obj.a了

watch的完整用法 |
---|
语法1 不要使用箭头函数来定义watch
代码语言:javascript复制watch:{
o1: () => {}
}
// 这里的this是全局对象,很多前端学JS几年,都没搞清楚this,忘了的同学可以写博客总结,我之前的博客中有介绍this,JS的三座大山,必须搞清楚this
可以使用以下语法
代码语言:javascript复制watch:{
o2: functions(value,oldValue){},
o3(){},
o4: [f1,f2],
o5: 'methodName',
o6: {handler:fn,deep:true,immediate:true},
'object.a':function(){}
}
语法2
代码语言:javascript复制vm.$watch('xxx',fn,{deep:...,immediate:..})
//其中'xxx'可以改为一个返回字符串的函数
computed和watch的区别 |
---|
1.computed是计算一个值的
2.computed在调用值的时候不需要加括号,可以当属性去用
3.computed的依赖会自动缓存
4.watch是监听一个值的
5.watch有两个选项,immediate:是否在第一次渲染的时候执行该函数,deep:是否监听对象里面的属性变化
6.watch在方法中会传入newVal和oldVal