Vue:学习笔记(六)-组件基础

Vue:学习笔记(六)-组件基础。

提醒

原帖完整收藏于IT老兵驿站,并会不断更新。

前言

最近在工作中频繁遇到组件,所以就没按照顺序,先总结组件这一章节的内容了,将来再做调整和修改。

(2018-10-24注:这一章粗读了两遍,感觉下面有好些内容都没有理解,有一些难度,看不明白就先修改一会儿,先干点别的。)

正文

基本示例

这是一个例子:

1
2
3
4
5
6
7
8
9
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

在我看来,组件就是模板、数据,加上对于数据处理的逻辑,这些显示和逻辑,基本是固定的,所以以组件的形式固化出来。(感觉,这话一说出来,立刻就清楚了)

1
2
3
<div id="components-demo">
<button-counter></button-counter>
</div>
1
new Vue({ el: '#components-demo' })

id等于“components-demo”是Vue对象的根元素,在它下面创建组件。

组件的复用

这里是将把组件应该理解成类,每一个实例是对象,对象之间是没有关系的。

data 必须是一个函数

只有将data实现为一个函数,才能实现上面的对象之间没有关系的复用。

组件的组织

这里有两种组件的注册类型:全局注册和局部注册。至此,我们的组件都只是通过 Vue.component 全局注册的:

1
2
3
Vue.component('my-component-name', {
// ... options ...
})

通过 Prop 向子组件传递数据

Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。为了给博文组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中:

1
2
3
4
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})

感觉这个props仅仅是用来约束,如果没有这个约束,所有在组件的属性中送过来的属性都会被接受。

单个根元素

这一章节讲了涉及多个元素的组件是如何组织的。
例如:

1
2
<h3>{{ title }}</h3>
<div v-html="content"></div>

如果模板涉及了多个元素,那么需要将这些元素放在一个根元素内,上面这个模板就涉及到两个元素,这个时候需要在外面再包裹一个元素:

1
2
3
4
<div class="blog-post">
<h3>{{ title }}</h3>
<div v-html="content"></div>
</div>

下面的例子涉及到如何设计传递的参数。

1
2
3
4
5
6
7
8
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:title="post.title"
v-bind:content="post.content"
v-bind:publishedAt="post.publishedAt"
v-bind:comments="post.comments"
</blog-post>

合理的设计应该是:

1
2
3
4
5
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-post>
1
2
3
4
5
6
7
8
9
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<div v-html="post.content"></div>
</div>
`
})

通过事件向父级组件发送消息

这段没想明白应该怎么去总结,完全照搬过来没有什么意义。

1
2
3
<button v-on:click="$emit('enlarge-text')">
Enlarge text
</button>

这个是孩子组件(位于父组件之内),可以使用$emit向父组件发送一个自定义的消息。

1
2
3
4
<blog-post
...
v-on:enlarge-text="postFontSize += 0.1"
></blog-post>

父组件使用v-on去监听这个事件。

使用事件抛出一个值

接着上面的例子,如果想给父组件发送消息的同时,传递参数,需要这样:
孩子组件:

1
2
3
<button v-on:click="$emit('enlarge-text', 0.1)">
Enlarge text
</button>

父组件:

1
2
3
4
<blog-post
...
v-on:enlarge-text="postFontSize += $event"
></blog-post>

这里第二个参数,可以是一个值,或者是一个方法

1
2
3
4
5
methods: {
onEnlargeText: function (enlargeAmount) {
this.postFontSize += enlargeAmount
}
}

好像不能是对象,这个还要确认一下。

在组件上使用 v-model

有一点含糊了,prop和v-model在这里有什么区别呢?这个部分讲的感觉又有点不清楚。

1
<input v-model="searchText">

等价于

1
2
3
4
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>

用在自定义的组件上(上面是标准的HTML元素),则是

1
2
3
4
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>

和上面大体接近,只是最后的$event有区别。

为了让它正常工作,这个组件内的 <input> 必须:
将其 value 特性绑定到一个名叫 value 的 prop 上
在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
写成代码之后是这样的:

1
2
3
4
5
6
7
8
9
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})

现在 v-model 就应该可以在这个组件上完美地工作起来了:
<custom-input v-model="searchText"></custom-input>

意思是:

1
2
3
4
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>

这么写和

1
<custom-input v-model="searchText"></custom-input>

这么写是一个意思,组件里面都要这么写:

1
2
3
4
5
6
7
8
9
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})

对event进行了一次转发。

通过插槽分发内容

这里讲的是如何把元素的内容传递给组件,叫做分发内容,使用<slot>这样的关键字来接收。

1
2
3
<alert-box>
Something bad happened.
</alert-box>

上面是一个自定义组件,给这个组件直接传递内容,会得到不正确的结果,需要有能接收这个内容的东西,这个就叫插槽。这个地方感觉讲的不清楚,自己尝试了一下。

如上图,这里并没有显示出内容来,没有用于接收的东西。

改为:

1
2
3
4
5
6
7
8
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})

则:

这样才显示出来。

动态组件

这段又没看懂。

解析 DOM 模板时的注意事项

这段和上面那段有关联,但是好像也是没写清楚,继续等待深度理解。

总结

断断续续,花了三天,终于大体看明白了(花了很多时间看这个slot,也把后面的关于slot的看了一遍,基本梳理清楚),感觉这一章节是Vue的核心内容,还需要不断完善这篇笔记。

参考

https://cn.vuejs.org/v2/guide/components.html