Vue 构造选项

new Vue()传入的参数,都有哪些呢


可以查看 官方文档 获取详细解释

常用的有以下组分

数据 DOM 生命周期钩子 资源 组合
data el created / beforeCreate components mixins
props template mounted / … directives extends
computed updated / … provide / inject
methods destroyed / …
watch activated / deactivated

数据

data

写作一个对象或一个函数,指明所属的 vue 实例所具有的变量值

1
2
3
4
5
6
7
8
9
data: {
n: 0
}

data(){
return {
n: 0
}
}

不论是以上哪种,一旦设置,n 立刻就会被 getter/setter 所代理,且访问 vm.n 就可以访问到 data 中所设置的 n

其中,在 vue 组件的定义中,只接受函数形式

而且对象形式有如下 bug

假设有一个 vue 组件,其 data 写作对象形式 n: 0

在 app.vue 中,import 了上述组件,假设命名为 demo

当 app.vue 渲染了两个 demo 时,这两个组件使用的是同一个对 n 的引用

一旦其中一个 n 变化,另一个也会同步

综上,建议 data 恒使用函数形式

props

用于向子组件传入参数

设有子组件有如下 props

1
2
3
Vue.component('props-demo-simple', {
props: ['size', 'myMessage']
})

则父组件在通过 html template 渲染子组件时,可以为该子组件传入 size 或 myMessage 属性,子组件可以像使用 data 一样直接使用 size 或 myMessage

可以为子组件的参数设置配置,参考配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Vue.component('props-demo-advanced', {
props: {
// 检测类型
height: Number,
// 检测类型 + 其他验证
age: {
type: Number,
default: 0,
required: true,
validator: function (value) {
return value >= 0
}
}
}
})

computed

计算属性,用于快速求出一个值

假设当前 vue 实例有以下组分

1
2
3
4
5
6
7
8
9
10
11
data(){
return {
n: 0,
m: 2
}
},
computed:{
mulNandM(){
return this.n*this.m
}
}

此时 mulNandM 尽管看起来像个方法,但是其结果会被缓存,并在其依赖的变量上设置监听

当该计算属性再次被访问时会直接返回对应结果,除非其监听的变量发生了变化

在计算属性外部,可以直接像访问成员变量一样访问计算属性

!!!注意!!!

computed 等内容严重依赖 this 指针,所以尽量不要使用箭头函数,因为箭头函数没有自己的 this 指针

下同,只要依赖 this 指针的,都强烈建议不要使用箭头函数

methods

顾名思义,就是 vue 实例的成员方法

上例中的计算属性也可以写作 methods

1
2
3
4
5
methods:{
mulNandM(){
return this.n*this.m
}
}

此时就必须加上括号,以方法形式调用,且不会缓存

一般用于执行复杂逻辑,简单的取值之类的建议使用计算属性

watch

监视属性,用于监视当前实例上的 data 的变化

例如,某 vue 实例有以下组分

1
2
3
4
5
6
7
8
9
10
11
data(){
return {
n: 0,
m: 2
}
},
watch:{
n(newval,oldval){
console.log(`n changed from ${oldval} to ${newval}`)
}
}

则当 n 变化的时候就会打印调试语句

若要在初始化时就执行 watch 选项,可以使用 immediate 参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
data(){
return {
n: 0,
m: 2
}
},
watch:{
n: {
handler: function(newval,oldval){
console.log(`n changed from ${oldval} to ${newval}`)
},
immediate: true
}
}

若要监听对象字段,可以用字符串显式指定

1
2
3
4
5
6
7
8
9
10
11
12
13
data(){
return {
obj: {
n: 0
},
m: 2
}
},
watch:{
'obj.n': function(newval,oldval){
console.log(`obj.n changed from ${oldval} to ${newval}`)
}
}

直接监听对象的话,其中字段值的改变不会触发监听函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
data(){
return {
obj: {
n: 0
},
m: 2
}
},
watch:{
obj: function(newval,oldval){
console.log(`obj changed from ${oldval} to ${newval}`)
}
}

vm.obj.n = 1 // 不会触发对 obj 的监听

因为对基本类型的 === 判断,是基于值的,而对象的判断是基于地址的

此时 obj 指向的地址没有改变,所以 vue 认为 obj 没有更新

如果要在修改其中字段时,也触发对 obj 的监听,可以使用 deep 参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
data(){
return {
obj: {
n: 0
},
m: 2
}
},
watch:{
obj: {
handler: function(newval,oldval){
console.log(`obj changed from ${oldval} to ${newval}`)
},
deep: true
}
}

vm.obj.n = 1 // 会触发对 obj 的监听

更多用法请看官方文档

DOM

el

用于指示当前 vue 实例在页面上的挂载目标

通常 el 可以

  1. 接受一个字符串作为其值,该字符串是一个 CSS 选择器
  2. 接受一个 HTMLElement 实例作为其值

也可以不指定该参数,而是通过 export default 暴露给父组件,让父组件决定自己所在的位置

template

提供一个字符串模板作为 Vue 实例的标识使用

模板将会替换挂载的元素,挂载元素的内容都将被忽略,除非模板的内容有分发插槽。

例如如下配置

1
2
3
4
5
template: `
<div>
233
</div>
`

但是在 vue 组件中,一般不在 script 部分指定该参数,而是在 HTML template 部分直接写 HTML 模板

生命周期钩子

官方文档提供了下图作为标准的生命周期图示

vue 生命周期

通过图片可以看出,所谓”钩子”,和 aop 编程中的”切点”概念相仿,都是指某个范围的切入口

此处即是两个过程交接之处,类似于绿皮火车相邻两节车厢之间是用钩子连接的

通过图示,可以发现 vue 实例挂载到页面是在 created 阶段后,beforeMount 阶段前完成的

此时判断 vue 实例有没有指示 el 选项

  • 若有 el 选项,则直接挂载并继续编译
  • 若无,则暂停当前实例的编译,直到显式挂载到页面上后才会继续编译

继续判断有没有 template 选项,此处将 template 选项和 HTML template 模板分别称为内部和外部 template

若有内部,则内部的优先级高,否则使用外部模板

若都没有,则报错

除此之外,update 的两个钩子也要注意,当且仅当发生了重新渲染的时候,也就是页面上内容要改变的时候,才会触发 update 相关的两个钩子

若仅修改数据而对页面没有影响,不会触发这两个钩子

资源

components

可以通过 components 选项引入子组件

示例如下

1
2
3
4
5
import sideBar from './components/common/sidebar'
export default {
components: {
sideBar
}

此时可以在 template 中使用

1
<sideBar></sideBar>

来引入子组件的 template 进行渲染

directives

用于自定义当前实例可用的模板指令

例子如下

1
2
3
4
5
6
7
8
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}

定义一个 focus 指令,当插入到页面中执行对应的函数,之后可以在模板中使用 v-focus

1
<input v-focus>

一般有 5 种钩子可选

  • bind,绑定到元素时调用
  • inserted,插入到元素时调用
  • update,所在组件的虚拟结点更新时调用,但可能在更新前被调用
  • componentUpdated,所在组件及其子组件全部更新后调用
  • unbind,解除绑定时调用

上述 5 种钩子,会被按顺序传入以下参数

  1. el,绑定的元素

  2. binding,该事件的具体数据

    假设现在有 v-on:click="hello",其中 hello 是一个方法

    1. name,指令名,不包括 v- 前缀

      本例中 binding.name === on

    2. value,指令的绑定值

      本例中 binding.value === hello

      若绑定的内容是可以立即求值的,则绑定其值

      v-on:click="1+1",value 就取值 2,而不是表达式 1+1

    3. oldValue,指令绑定的前一个值,仅在发生更新时,即 update 或 componentUpdated 钩子中传入

    4. expression,字符串形式的指令表达式

      沿用 2 中的例子,分别取 hello1+1

    5. arg,传给指令的参数

      本例中 binding.arg === 'click'

    6. modifiers,一个包含修饰符的对象

      例如在 v-my-directive.foo.bar 中,有

      1
      2
      3
      4
      binding.modifiers === {
      foo: true,
      bar: true
      }
  3. vnode,所在的虚拟结点

  4. oldVnode,上一个虚拟结点

    仅在发生更新时,即 update 或 componentUpdated 钩子中传入

主要用于减少 DOM 操作

每个指令都可以绑定专有的钩子函数,详见 文档

组合

mixins

将待混入的对象混入到 vue 实例中,相同的属性会智能合并,即

  • 对于 data,覆盖相同的,保留不同的
  • 对于 methods 和生命周期钩子函数等,全部保留
1
2
3
4
5
6
7
const mixin = {
created: function () { console.log(1) }
}
const vm = new Vue({
created: function () { console.log(2) },
mixins: [mixin]
})

如上例,最终两个 created 阶段的 function 都会在 vm 实例的 created 阶段执行,输出 1和2

记得加方括号

extends

与 mixins 类似,使得当前实例继承另一个实例的所有值

1
2
3
4
5
6
7
const CompA = { ... }

// 在没有调用 `Vue.extend` 时候继承 CompA
const CompB = {
extends: CompA,
...
}

如上例,CompA 的所有内容会在 CompB 内被展开

provide / inject

由父组件提供(provide)一个对象或方法,并注入(inject)到子组件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
export default {
provide () {
return {
reload: this.reload
}
},
data () {
return {
isRouterAlive: true
}
},
methods: {
reload () {
this.isRouterAlive = false
this.$nextTick(function () {
this.isRouterAlive = true
})
}
}
}

如上,父组件提供了一个 reload 方法实现局部刷新

然后在子组件中

1
2
3
export default {
inject: ['reload']
}

就成功向子组件注入了 reload 方法,在子组件中也可以通过 this.reload() 来实现局部刷新了

注意,此处传递依然遵循 JS 传递规则,即 3 个基本类型传值,其余传引用


感谢阅读

--It's the end.Thanks for your read.--