声明式渲染与 data 函数

2020-01-13 16:36:44 浏览数 (1)

代码语言:javascript复制
目录

声明式渲染
data 必须是一个函数
为什么 data 必须是一个函数?
提一个 data 作为箭头函数的写法
源码

声明式渲染

这是学习vue开发,必先了解的第一个特征。如前已经实现的App.vue组件,已经包括声明式渲染:

代码语言:javascript复制
<template>
  <div>{{message}}</div>
</template>

<script>
export default {
  name: 'App',
  components: {},
  data: () => ({
    message:'hi'
  }),
};
</script>

message是在data中声明的一个文本,直接以{{message}}内嵌于模板中。当message改变时,模板会自动更新。

这是由于vue2基于Object.defineProperty()data中的每个属性定义了一对setter/getter。当模板渲染时,getter被调用,视图依赖的数据项被记录下来;当数据改变时,检查改变的数据有没有被依赖,如果有,重新渲染视图。

这就是MVVM框架在viewdata-view之间实现的BI-DataBinding机制。

data 必须是一个函数

如果直接返回一个对象,在vue-cli3中,编译阶段直接就报错了。

vue组件的导出是唯一的,如果返回的是一个对象,那么所有该组件的实例将共享同一块内存的数据对象,改变任何一个组件实例的数据,其它均会受到影响。

例如,将App.vue修改为:

代码语言:javascript复制
<template>
  <div>
    <HellWorld></HellWorld>
    <HellWorld></HellWorld>
    <HellWorld></HellWorld>
  </div>
</template>

<script>
import HellWorld from './HelloWorld.vue'
export default {
  name: 'App',
  components: {HellWorld},
};
</script>

并新增一个HelloWorld.vue组件:

代码语言:javascript复制
<template>
  <div @click="message ='!'">{{message}}</div>
</template>

<script>
const data = {
  message:'hi'
}
export default {
  name: 'HelloWorld',
  components: {},
  data: ()=>data,
};
</script>

当单击div时,message尾部追求一个符号。data虽然是一个函数,但是返回的却是一个const对象。const data在项目仅会声明一次,在多个组件实例中是唯一的。

如图所示,单击任何一个组件,其它组件亦受影响:

解决方法也很简单,直接让data返回一个局部的临时对象:

<script> // const data = { // message:'hi' // } export default { name: 'HelloWorld', components: {}, data: ()=>({ message:'hi' }), }; </script>

运行效果:

为什么 data 必须是一个函数?

这是vue2内部源码要求的。通过查看Vue->_init->initState->initData源码:

发现,如果data未定义,一个默认的data对象会被创建,否则data会被当成一个function被调用。

而在initData中,data function被以call的方式调用了:

其中pushTarget(),疑为对data observer的处理。

即使data function是一个函数,也仅是在初始化时调用一次,然后函数返回的值就一直保存在了vm._data上。在后续的运行时数据发生时,改变的也是vm._data,这个对象在组件的生命内,其引用一直保持不变。

提一个 data 作为箭头函数的写法

细心的读者会发现,data function没有return

代码语言:javascript复制
  data: ()=>({
    message:'hi'
  }),

这是一个箭头函数,当函数体代码只有一句时, return可以省略。

那么,花括号外面的()能不能省略?

不能,因为函数返回的是一个字面值对象。如果这里的()省略了,编译器不清楚后面的{}究竟表示对象,还是函数的边界了。

源码

https://git.code.tencent.com/shiqiaomarong/vue-go-rapiddev-example/tags/v20200108

参考链接

  • https://www.liaoxuefeng.com/wiki/1022910821149312/1031549578462080
  • https://juejin.im/entry/59225ff8a22b9d005885cb15
  • https://blog.rxliuli.com/p/2f1f8cdf/

0 人点赞