vue构造选项

options

1
const vm = new Vue(option)

options 的五类属性

数据:data、props、propsData、computed、methods、watch

DOM:el、template、render、renderError

生命周期钩子 :beforeCreate、created、before Mount、mounted、beforeUpdate、updated、activated、deactivated、beforeDestroy、destroyed、errorCaptured

资源:directives、filters、components

组合:parent、mixins、extends、provide、inject

其他:暂且不表

入门属性

  • el - 挂载点:与 $mount 有替换关系
  • data - 内部数据:支持对象和函数,优先用函数
  • methods - 方法: 事件处理函数或者是普通函数
  • components : 使用 Vue 组件,注意大小写
  • 四个钩子
    • created - 实力出现在内存中
    • mounted - 实力出现在页面中
    • updated - 示例更新了
    • destroyed - 实例消亡了
  • props - 外部属性

components 三种引入方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 1 优先使用
import Demo from "./Demo.vue"

new Vue({
components:{
Frank1: Demo
},
template:`
<div>
...
<Frank/>
...
</div>
`
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 2
Vue.component('Frank2',{
template:`
<div>demo022</div>
`
})

new Vue({
template:`
<div>
...
<Frank2/>
...
</div>
`
})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 3
const x = {
template: `
<div>demo333</div>
`
}

new Vue({
components:{
Frank3: x
},
template:`
<div>
...
<Frank3/>
...
</div>
`
})

四个钩子

demo

created - 实例出现在内存中

mounted - 实例出现在页面中

updated - 实例更新了

destroyed - 实例从页面和内存中消亡了

props

props 可以是数组或对象,用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。

1
2
3
message="n"  // 传入字符串
:message="n" // 传入 this.n
:fn="add" // 传入 this.add 函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Demo.vue
<template>
<div>
”这是 demo 的内部“,
n = {{ message }}
<button @click="fn">call back</button>
</div>
</template>

<script>
export default {
props: ['message', 'fn']
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// main.js
import Demo from './Demo.vue'
new Vue({
components: {Demo},
data() {
return {n: 5}
},
template: `
<div>
{{ n }}
<Demo :message="n" :fn="add"/>
</div>
`,
methods: {
add() {
this.n += 1
}
}
}).$mount('#app2')

进阶属性

computed - 计算属性

被计算出来的属性就是计算属性

  • 当其依赖的属性的值发生变化的时,计算属性会重新计算。
  • 如果依赖的属性没有变化,就不会重新计算,使用缓存中的属性值。

computed 比较适合对多个变量或者对象进行处理后返回一个结果值,也就是数多个变量中的某一个值发生了变化则我们监控的这个值也就会发生变化。

例1. getter / setter -demo

用户名展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 需引用完整版 vue
Vue.config.productionTip = false;

new Vue({
data: {
user: {
email: "fangyinghang@qq.com",
nickname: "方方",
phone: "13812312312"
}
},
computed: {
displayName: {
get() {
const user = this.user;
return user.nickname || user.email || user.phone;
},
set(value) {
console.log(value);
this.user.nickname = value;
}
}
},
template: `
<div>
{{displayName}}
<div>
{{displayName}}
<button @click="add">set</button>
</div>
</div>
`,
methods: {
add() {
console.log("add");
this.displayName = "圆圆";
}
}
}).$mount("#app");

例2 使用 computed - demo

用 computed 筛选男女

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Vue.config.productionTip = false;

let id = 0;
const createUser = (name, gender) => {
id += 1;
return { id: id, name: name, gender: 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}}</li>
</ul>

</div>
`
}).$mount("#app");

例2.1不使用 computed - demo

不用 computed 筛选男女

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
Vue.config.productionTip = false;
let id = 0;
const createUser = (name, gender) => {
id += 1;
return {
id: id,
name: name,
gender: 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 的值是意外的值");
}
},
},
methods: {
setGender(string) {
this.gender = string;
},
},

template: `
<div>
<div>
<button @click="setGender('') ">全部</button>
<button @click="setGender('male')">男</button>
<button @click="setGender('female')">女</button></div>
<ul>
<li v-for="(u,index) in displayUsers" :key="index">{{u.name}} - {{u.gender}}</li>
</ul>

</div>
`,
}).$mount("#app");

官方 计算属性和侦听器

watch - 侦听器

  • 使用watch来响应数据的变化,也就是当数据变化时,执行一个函数。
  • 一般用于异步或者开销较大的操作
  • watch 中的属性 一定是 data 中 已经存在的数据
  • 当需要监听一个对象的改变时,普通的 watch 方法无法监听到对象内部属性的改变,只有 data 中的数据才能够监听到变化,此时就需要 deep 属性对对象进行深度监听

选项:deep

为了发现对象内部值的变化,可以在选项参数中指定 deep: true。注意监听数组的变更不需要这么做。

1
2
3
4
5
vm.$watch('someObject', callback, {
deep: true
})
vm.someObject.nestedValue = 123
// callback is fired

选项:immediate

在选项参数中指定 immediate: true 将立即以表达式的当前值触发回调:

1
2
3
4
vm.$watch('a', callback, {
immediate: true
})
// 立即以 `a` 的当前值触发回调

注意在带有 immediate 选项时,你不能在第一次回调时取消侦听给定的 property。

1
2
3
4
5
6
7
8
9
// 这会导致报错
var unwatch = vm.$watch(
'value',
function () {
doSomething()
unwatch()
},
{ immediate: true }
)

如果你仍然希望在回调内部调用一个取消侦听的函数,你应该先检查其函数的可用性:

1
2
3
4
5
6
7
8
9
10
var unwatch = vm.$watch(
'value',
function () {
doSomething()
if (unwatch) {
unwatch()
}
},
{ immediate: true }
)

vm.$watch

例1. 撤销-demo

https://codesandbox.io/s/lucid-shamir-cpcw3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
Vue.config.productionTip = false;

new Vue({
data: {
n: 0,
history: [],
inUndoMode: false,
},
watch: {
n: function (newValue, oldValue) {
console.log(this.inUndoMode);
if (!this.inUndoMode) {
this.history.push({ from: oldValue, to: newValue });
}
},
},
// 不如用 computed 来计算 displayName
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-demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 引用完整版 Vue,方便讲解
import Vue from "vue/dist/vue.js";

Vue.config.productionTip = false;

new Vue({
data: {
user: {
email: "fangfang@qq.com",
nickname: "方方",
phone: "13812312312"
},
displayName: ""
},
watch: {
"user.email": {
handler: "changed",
immediate: true // 第一次渲染是也触发 watch
},
"user.nickname": {
handler: "changed",
immediate: true // 第一次渲染是也触发 watch
},
"user.phone": {
handler: "changed",
immediate: true // 第一次渲染是也触发 watch
}
},
// 不如用 computed 来计算 displayName
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");

directives - 指令

  • 内置指令 v-if / v-for / v-bind / v-on
  • 自定义指令
  • 指令是为了减少重复的 dom 操作

mixin - 混入

  • 重复三次之后的出路
  • 混入 V.S. 全局混入
  • 选项自动合并
  • 混入就是为了减少重复的构造选项

还是使用上一个例子:

1
2
3
4
5
6
7
8
9
10
11
const MyVue = Vue.extend({
data(){ return {name:'', time: undefined} },
created(){
if(!this.name){ console.erroe('no name!') }
this.time = new Date()
},
beforeDestroy(){
const duration = (new Date()) - this.time
console.log(`${this.time} 存活时间 ${duration}`)
}
})

extends - 继承

  • 先了解一下 Vue.extend
  • 你觉得用了 mixin 还是重复
  • 于是你自己写了一个 View, 他继承 Vue
  • 你还可以预先定义其他构造选项
  • 继承就是为了减少重复的构造选项
  • 那为什么不用 ES6 的extends 呢?

provide / inject

  • 爷爷想和孙子讲话怎么办
  • 祖宗想跟他的所有后代讲话怎么办
  • 答案是全局变量,但是全局变量太 low
  • 所以我们需要 局部的全局变量