# Vue2.0进阶
# 一、vue实例与vue组件
1、组件是扩展的 Vue 构造器,“扩展”的含义是用一些“默认”属性、方法以及钩子函数来“定制” Vue 构造器,其语法自然就和 Vue 实例化的语法类似。
2、模板中的<MyComponent...>是实例化组件的一种方法(另一种方法是 render 函数中使用 createElement 创建),实例化的组件就是一个 Vue 实例。
//main.js根实例
import Vue from 'vue'
import App from './App'
import router from './router'
new Vue({//这里就是一个vue实例
el: '#app',//el挂载点,根实例特有
router, //路由,根实例特有
components: { App },
template: '<App/>',//此处引根组件
})
//app.vue单文件组件
<template>
<div id="app">
<div class="welcome">welcome! {{name}}, you are {{age}} years old</div>
</div>
</template>
<script>
export default { //输出为对象
name: 'App', //组件名字
data:function(){ //data为函数
return {
name:'wangyue',
age:'25'
}
},
}
</script>
<style>
.welcome{
font-size: 32px;
color: blueviolet;
}
</style>
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
# 二、组件间通信
# 1、props和$emit
父子通讯
props:父组件单向数据流向子组件
$emit:子组件通过事件流向父组件
<!-- 父组件 -->
<template>
<div>
<compB :title="value" @more="onMore"/>
</div>
</template>
<script>
import compB from '/compB'
export default{
name: 'compA',
data(){
return {
value: ""
}
},
methods:{
onMore(value){
console.log('value', value)
}
}
}
</script>
<!-- 子组件 -->
<template>
<div>
<div>{{title}}</div>
<button @click="handleMore">查看更多</button>
</div>
</template>
<script>
export default{
name:'compB',
props:{
title:{
type: String,
default: 'Jian'
}
},
methods:{
handleMore(){
this.$emit('more', 'message to father')
}
}
}
</script>
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
# 2、$parent/$children
父子通讯
- $parent可以用来从一个子组件访问父组件的实例,提供了一种随时访问父级组件的机会,可以替代将数据以props的方式传入子组件的方式
- $children可以遍历当前组件的全部子组件,$children并不保证顺序,也不是响应式的。vue3中移除了实例的$children属性,推荐使用$refs来访问子组件的实例
<!-- 父组件 -->
<template>
<child-comp></child-comp>
</template>
<script>
import childComp from './child'
export default {
name: 'parentComp',
data(){
return {
parentMsg: 'father component'
}
},
components: {
childComp
},
mounted(){
//取子组件的属性值
console.log(this.$children[0].childMsg)
}
}
</script>
<!-- 子组件 -->
<template>
<span>{{magTxt}}</span>
</template>
<script>
export default {
name: 'childComp',
data(){
return {
msgTxt: ''
childMsg: 'child component'
}
},
created(){
//取父组件的data属性值
this.msgTxt = this.$parent.parentMsg
}
}
</script>
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
# 3、$root/$refs
父子通讯
- $root:每个new Vue实例的子组件中都有$root属性,可以通过$root属性访问根实例,若当前组件没有父组件实例,则$root为自己
- $refs:可以通过ref为子组件赋予一个id引用,从而实现在js里直接访问一个子组件。$refs返回一个对象,包括注册过ref的所有dom元素和组件实例,用于父组件访问子组件。
new Vue({
data:{
foo: 1
},
computed: {
bar: function(){/* */}
},
methods: {
baz: function(){/* */}
}
})
//$root使用实例
console.log(this.$root.foo)
console.log(this.$root.bar)
console.log(this.$root.baz())
this.$root.foo = 2
//$refs使用: 父组件
<template>
<div>
<my-component ref="childrenCompA"></my-component>
<my-component ref="childrenCompB"></my-component>
</div>
</template>
<script>
export defalut {
methods: {
getMsg(){
return this.$refs.childrenCompA.msg + this.$refs.childrenCompB.msg
}
}
}
</script>
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
# 4、provide/inject
隔代通讯:祖先组件通过provide来提供变量,然后在子孙组件中通过inject来注入变量。provide/inject主要解决了跨级组件间的通信问题,不过主要使用场景为子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
- provide选项是一个对象或者返回一个对象的函数,该对象包含可注入其子孙的属性。
- inject选项是一个字符串数组或一个对象
- provide和inject绑定不是可响应式的,但传入的可监听对象的property仍然可响应
<!-- 父组件 -->
<template>
<com-a></com-a>
</template>
<script>
import ComA from './a'
export default {
name: 'home',
components: {
ComA
},
/*
provide:{
'a': 'Hello',
'show': val => !val
}
*/
provide(){
return {
'a': 'Hello',
'show': val => !val
}
}
}
</script>
<!-- 子组件 -->
<template>
<div>
<button @click="showFn">{{a}}</button>
</div>
</template>
<script>
import ComA from './a'
export default {
/*
inject:{
a_child: 'a',
show_child: 'show'
}
*/
inject:['a', 'show'],
methods:{
showFn(){
this.show('xxx')
}
}
}
</script>
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
# 5、$attrs/$listeners
隔代通讯
- $attrs:存放的是父组件中绑定的非Props属性
- 包含了父作用域中不被prop所识别(且获取)的特性绑定(class和style除外)
- 当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定(class和style除外)
- 可以通过v-bind=“$attrs”传入子组件,通常配合inheritAttrs选项一起使用
- $listeners:存放的是父组件中绑定的非原生事件,vue3移除
- 包含了父作用域中的(不含.native修饰器的)v-on事件监听器
- 可以通过v-on=“$listeners”传入子组件
<!-- 父组件 -->
<template>
<div>
<child-a :name="name" :age="age" :job="job"
title="this is a title" @click="console.log("hello")"></child-a>
</div>
</template>
<script>
import ChildA from './ChildA'
export default {
components:{
ChildA
},
data(){
return {
name: 'tao',
age: "28",
job: "worker"
}
}
}
</script>
<!-- 子组件 -->
<template>
<div>
<child-b v-bind="$attrs" v-on="$listeners"></child-b>
</div>
</template>
<script>
import ChildB from "./ChildB"
export default{
name: "child-a",
components: {
ChildB
},
created(){
console.log(this.$attrs) //{name: "tao", age: "28", job: "worker", title: "this is title"}
this.$listeners.click() //Hello
}
}
</script>
<!-- 孙组件 -->
<template>
<div>
<p>B-listeners: {{this.$listeners.click()}}</p>
</div>
</template>
<script>
export default {
props: ["name"], //name作为props属性绑定
created(){
console.log(this.$attrs) //{age: "28", job: "worker", title: "this is title"}
this.$listeners.click() //hello
}
}
</script>
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
# 6、bus/js对象
组件间通讯
事件总线EventBus
通过一个空的vue实例作为中央事件总线,用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级通信。注意销毁自定义事件,避免内存泄露。
vue3中移除了
$on
,$off
,$once
三个vue实例方法,无法使用中央事件总线,可以通过使用外部库来替换。
局部js对象
- 利用esmodule引用特性,声明一个包含属性和方法的对象,在多组件共享,适用于功能复杂且与模块无关的模块开发场景
- 对象中的数据为非响应式的
//事件总线
let Bus = new Vue();
//componentA
Bus.$emit('add-todo', {text: this.newTodoText})
//componentB
Bus.$on('add-todo', this.addTodo)
Bus.$off('add-todo', this.addTodo) //移除事件
//局部js对象
//shareState.js
const store = {
state: {
user: []
},
setUsers(users){
this.state.users = users
}
}
export default store
//componentA
import shareState from '@/shareState'
export default {
data(){
return {
sharedState: shareState.state
}
},
methods:{
todo(value){
shareState.setUsers(value)
}
}
}
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
# 7、Vuex
组件间通讯
# 8、缓存
localStorage, sessionStorage
# 三、自定义指令
# 1、指令添加
- 全局添加:Vue.directive(id, [definition])
- 注册或获取全局指令
- {string} id
- {Function | Object} [definition]:指令对象,有5个可选钩子
- 局部添加:组件内directives属性
//全局指令
Vue.directive('focus', {
inserted:function(el){
el.focus()
}
})
//局部指令
export default {
directives: {
focus: {
inserted: function(el){
el.focus()
}
}
}
}
//使用
<input v-focus>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2、钩子函数
//vue2全量钩子函数
{
bind(){},
inserted(){},
update(){},
compotentUpdated(){},
unbind(){}
}
//注意:vue3中钩子api进行了调整,与生命周期靠拢,无法兼容
{
beforeMount(){}, //bind
mounted(){}, //inserted
beforeUpdate(){},
undated(){}, //componentUpdated
beforeUnmount(){},
unmounted(){} //unbind
}
//简写,只想在bind和update时触发相同行为,不关心其他的钩子
Vue.directive('focus', function(el, binding){
el.style.backgroundColor = binding.value
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- bind:只调用一次,指令第一次绑定到元素时调用,在这里可以进行一次性初始化操作。
- inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)
- update:所在组件的VNode更新时调用,但是可能发生在其子VNode更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新后的值来忽略不必要的模版更新。
- compotentUpdated:指令所在组件的VNode以及子VNode全部更新后调用。
- unbind:只调用一次,指令与元素解绑时调用。
# 3、钩子函数入参
el:指令绑定的元素,可以直接用来操作dom
binding:一个对象,包含如下property:
- name:指令名,不包含v-前缀
- value:指令的绑定值,eg:v-xx=”1+2“,value=3
- oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子中可用,无论值是否改变。
- expression:字符串形式的指令表达式,eg:v-xx=”1+2“,expression="1+2"
- arg:传给指令的参数,eg:v-xx:foo,arg=“foo”
- modifiers:一个包含修饰符的对象,eg:v-xx.foo.bar中,修饰符对象为{foo:true, bar:true}
vnode:vue编译生成的虚拟节点
oldVnode:上一个虚拟节点,仅在update和componentUpdated钩子中可用
# 4、指令传参
- 动态指令参数:通过[]传入动态参数
- 对象字面量:传入一个 JavaScript 对象字面量
<div v-demo="{color: 'white', text: 'hello'}"></div>
Vue.directive('demo', function(el, binding){
console.log(binding.value.color) //"white"
console.log(binding.value.text) //"hello"
})
<div id="app">
<p v-pin:[direction]="200">text</p>
</div>
Vue.direction('pin', {
bind: function(el, binding, vnode){
el.style.position = 'fixed'
var s = (binding.arg == 'left' ? 'left' : 'top')
el.style[s] = binding.value + 'px'
}
})
new Vue({
el: '#app',
data: function(){
return {
direction: 'left'
}
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 5、典例
//按钮防重自定义指令
Vue.directive('preventClick', {
inserted(el, binding){
el.addEventListener('click',()=>{
if(!el.disabled){
el.disabled = true
el.style.cursor = 'not-allowed'
setTimeout(()=>{
el.disabled = false
el.style.cursor = 'pointer'
}, binding.value || 2000)
}
})
}
})
<el-button v-preventClick="3000">click</el-button>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 四、插槽用法
插槽是Vue组件的一种机制,插槽提供了一个讲内容放置到新位置或组件更通用的出口
# 1、插槽分类
具名插槽:通过name指定插槽名字
- 组件支持多个插槽,组件内未命名的为默认插槽,被隐式命名为default,其他不同的插槽需要显示命名
- 插槽使用slot组件,name属性命名插槽,父组件使用v-slot指令
- v-slot指令只能添加在
<template>
上,例外为作用域插槽只有默认插槽情况
作用域插槽:通过v-slot指令的值指定作用域变量的名称
有时让插槽内容(父组件)能够访问子组件中才有的数据,为了让子组件的数据/方法能够在父组件的插槽内容中可用,可以将这些数据/方法作为slot元素的属性绑定上去,使用v-slot指令的值指定作用域变量的名称
<!-- 具名插槽:子组件 -->
<template>
<div>
<h2>
<slot name="header">Title</slot>
</h2>
<slot>default</slot>
</div>
</template>
<!-- 具名插槽:父组件 -->
<template>
<componA>
<template v-slot:header>
My name is Jian
</template>
<!-- The code below goes into the default slot -->
<img src="./img.jpg">
</componA>
</template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- 作用域插槽:子组件 -->
<template>
<span>
<slot v-bind:user="user">
{{user.lastName}}
</slot>
</span>
</template>
<!-- 作用域插槽:父组件 -->
<template>
<current-user>
<template v-slot:default="slotProps">
{{slotProps.user.firstName}}
</template>
</current-user>
</template>
<!-- 只有默认插槽的缩写,直接放组件上,无需使用template -->
<current-user v-slot="slotProps">
{{ slotProps.user.firstName }}
</current-user>
<!-- 对象解构, #简写 -->
<current-user #default="{user}">
{{ user.firstName }}
</current-user>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 2、插槽用途
# 1、组件复用
插槽允许通过html片段或其他组件自定义内容,可以方便的支持自定义内容并提供呢统一的属性
<!-- 按钮封装 -->
<template>
<button>
<slot>添加</slot>
</button>
</template>
<!-- 调用:带图标的按钮 -->
<template>
<my-button>
<img src="/img.jpg">
</my-button>
</template>
<!-- 尾部添加按钮关闭弹框 -->
<template>
...
<div class="modal-footer">
<slot name="footer" :closeModal="closeModal"></slot>
</div>
</template>
<script>
export default {
methods: {
closeModal(){/* */}
}
}
</script>
<!-- 父组件调用 -->
<template #footer="{closeModal}">
<button @click="closeModal">
关闭对话框
</button>
</template>
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
# 2、无渲染组件
利用插槽,可以创建无渲染组件,用于业务逻辑和视图的解耦:只提供函数而不渲染自己html模版的组件。数据和事件以及dom元素内容全部由父组件的插槽内容提供。
- 数据和事件:作用域插槽可以将数据和事件从子组件传递给父组件,这就相当于对外暴露了接口。
- dom元素:将
HTML
中的DOM
以及CSS
交给父组件(调用方)去维护,子组件通过<slot>
标签插入。
<!-- 两组件,业务逻辑相同,视图不同,利用插槽剥离业务逻辑代码进行复用 -->
<!-- 子组件:业务逻辑代码,开关切换 -->
<template>
<div class="toggle-container">
<slot :currrentState="currentState" :setOn="openState"
:setOff="closeState" :traggle="toggle"></slot>
</div>
</template>
<script>
export default {
props: {
state: {
type: Boolean,
default: false
}
},
data(){
return {
currentState: this.state
}
},
methods: {
openState(){
this.currentState = true
},
closeState(){
this.currentState = false
},
toggle(){
this.currentState = !this.currentState
}
}
}
</script>
<!-- 父组件调用:通过作用域插槽调用子组件函数,通过插槽传递dom元素 -->
<template>
...
<template v-slot:default="{currentState, setOn, setOff, toggle}">
<button @click="toggle">切换</button>
<button @click="setOn">打开</button>
<button @click="setOff">关闭</button>
<div v-if="currentState">已打开</div>
<div v-else>已关闭</div>
</template>
</template>
<!-- 无渲染组件:使用render去除模版,使用this.$scopedSlots(作用域插槽)属性替代slot组件 -->
<script>
export default {
props: {
state: {
type: Boolean,
default: false
}
},
data(){
return {
currentState: this.state
}
},
//(createElement: () => VNode) => VNode
/* render: function (createElement) {
return createElement('h1', this.blogTitle)
}*/
render(){
return this.$scopedSlots.default({
currentState: this.currentState,
setOn: this.openState,
setOff: this.closeState,
toggle: this.toggle
})
},
methods: {
openState(){
this.currentState = true
},
closeState(){
this.currentState = false
},
toggle(){
this.currentState = !this.currentState
}
}
}
</script>
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# 五、vue修饰符
# 1、表单修饰符
- v-model.lazy:改变输入框的值时value不会改变,当光标离开输入框时,v-model绑定的值value才会改变
- v-model.trim:类似于trim(),把v-model绑定的值的首尾空格过滤
- v-model.number:将值转换为数字
- 先输入数字的话,只取前面数字部分
- 先输入字母的话,number修饰符无效
- v-bind.sync:对一个prop进行双向绑定的简写,父组件通过绑定属性的方式向子组件传值,而在子组件中可以通过$emit向父组件通信,通过这种间接的方式改变父组件的data,从而实现子组件改变props的值
- 子组件传递的事件名必须是update:value,其中value必须与子组件中的props中声明的名称完全一致
- 带有.sync修饰符的v-bind不能和表达式一起使用(可使用计算属性),必须使用要绑定的属性名
<!-- 父组件 -->
<child-com :age="age" @setAge="res => {age = res}"></child-com>
<!-- 子组件 -->
this.$emit('setAge', 18)
<!-- 等价写法 -->
<child-com :age.sync="age"></child-com>
this.$emit('update:age', 18)
2
3
4
5
6
7
8
# 2、事件修饰符
- v-on.stop:阻止事件冒泡,event.stopPropagation()方法
- v-on.prevent:阻止原生事件,event.preventDefault()方法
- v-on.self:点击事件绑定的本身才会触发事件
- v-on.capture:反向冒泡,事件默认是由里往外冒泡,使用.capture修饰符时候,事件触发由外往内捕获
- v-on.passive:当监听元素的滚动事件的时候,会一直触发onscroll事件,在移动端页面会卡顿,使用.passive会直接执行默认行为,不等onscroll事件完成。
- 常用于监听scoll、touchmove事件使用
- 每次事件产生,浏览器都会去查询一下是否有preventDefault阻止该次事件的默认动作,通过passive将内核线程查询跳过,可以大大提升滑动的流畅度
- passive和prevent冲突,不能同时绑定在一个监听器上
- .native:在某个组件的根元素上监听一个原生事件。一般将事件绑定用在html原生标签**,**在组件标签上使用的时候,就要加上native修饰符,这样就可以像原生标签一样使用事件绑定
<!-- 执行顺序:1,2,4,3 -->
<div @click.capture="shout(1)">
obj1
<div @click.capture="shout(2)">
obj2
<div @click="shout(3)">
obj3
<div @click="shout(4)">obj4</div>
</div>
</div>
</div>
<!-- 滚动事件的默认行为(即滚动行为)将会立即触发,不会等待onScroll完成 -->
<!-- 其中包含event.preventDefault()情况 -->
<div v-on:scroll.passive="onScroll">滑动</div>
<!-- myself-button 可绑定click事件,类似button -->
<myself-button @click.native="add('组件标签,包含native的点击')" /></myself-button>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 3、鼠标按键修饰符
- @click.left:鼠标左键
- @click.rigth:鼠标右键
- @click.midele:鼠标中键
# 4、键值修饰符
- @keydown/@keyup:键盘事件监听
- 按键码:.enter/.tab/.delete/.space等
- 系统修饰键:.ctrl/.alt/.shift/.meta
- .exact:控制精确的系统修饰符组合触发的事件
<button @keyup.enter="submit">key为Enter时触发</button>
<div @click.ctrl="submit">ctrl + click时触发</div>
<button @click.ctrl.exact="submint">有且只有ctrl被按下时触发</button>
<button @click.exact="submint">没有任何系统修饰符被按下时触发</button>
2
3
4
# 六、特殊组件
# 1、动态组件
- component组件配合is属性进行组件动态切换
- 属性is:可以为组件名字或组件对象
- 使用keep-alive组件动态组件:用于保留组件状态或避免重新渲染
- include:字符传或正则,名称匹配的组件被缓存
- exclude:字符传或正则,名称匹配的组件不被缓存
- max:缓存最大组件数目
<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>
import compA from './compA'
import compB from './compB'
export default {
data(){
return {
currentTabComponent: compA //组件对象
//currentTabComponent: 'tab-home' //组件名字
}
},
components: {
"tab-home": {
template: "<div>Home component</div>"
}
}
}
<!-- 基本 -->
<keep-alive>
<component :is="view"></component>
</keep-alive>
<!-- 多个条件判断的子组件 -->
<!-- if值变化时,comp-a和comp-b不会重新渲染,执行全部生命周期 -->
<keep-alive>
<comp-a v-if="a > 1"></comp-a>
<comp-b v-else></comp-b>
</keep-alive>
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
# 2、异步组件
组件拆分,异步加载使用:以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义,Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。
/* 全局定义异步组件 */
Vue.component(
'async-webpack-example',
// 这个动态导入会返回一个 `Promise` 对象。
() => import('./my-async-component')
)
/* 局部定义异步组件 */
new Vue({
// ...
components: {
'my-component': () => import('./my-async-component')
}
})
/* 完整的工程函数 */
const AsyncComponent = () => ({
// 需要加载的组件 (应该是一个 `Promise` 对象)
component: import('./MyComponent.vue'),
// 异步组件加载时使用的组件
loading: LoadingComponent,
// 加载失败时使用的组件
error: ErrorComponent,
// 展示加载时组件的延时时间。默认值是 200 (毫秒)
delay: 200,
// 如果提供了超时时间且组件加载也超时了,
// 则使用加载失败时使用的组件。默认值是:`Infinity`
timeout: 3000
})
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
# 3、函数式组件
无状态 (没有响应式数据),也没有实例 (没有 this
上下文),接受props数据。
Vue.component('my-component', {
functional: true,
// Props 是可选的
props: {
// ...
},
// `render` 函数返回虚拟节点使它们渲染的代价更小
// 为了弥补缺少的实例
// 提供第二个参数作为上下文
render: function (createElement, context) {
// ...
}
})
2
3
4
5
6
7
8
9
10
11
12
13