Vue:学习笔记(六)-组件基础
提醒
原帖完整收藏于IT老兵驿站,并会不断更新。
前言
最近在工作中频繁遇到组件,所以就没按照顺序,先总结组件这一章节的内容了,将来再做调整和修改。
(2018-10-24注:这一章粗读了两遍,感觉下面有好些内容都没有理解,有一些难度,看不明白就先修改一会儿,先干点别的。)
正文
基本示例
这是一个例子:
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
在我看来,组件就是模板、数据,加上对于数据处理的逻辑,这些显示和逻辑,基本是固定的,所以以组件的形式固化出来。(感觉,这话一说出来,立刻就清楚了)
<div id="components-demo">
<button-counter></button-counter>
</div>
new Vue({ el: '#components-demo' })
id等于“components-demo”是Vue对象的根元素,在它下面创建组件。
组件的复用
这里是将把组件应该理解成类,每一个实例是对象,对象之间是没有关系的。
data 必须是一个函数
只有将data实现为一个函数,才能实现上面的对象之间没有关系的复用。
组件的组织
这里有两种组件的注册类型:全局注册和局部注册。至此,我们的组件都只是通过 Vue.component 全局注册的:
Vue.component('my-component-name', {
// ... options ...
})
通过 Prop 向子组件传递数据
Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。为了给博文组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中:
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
感觉这个props仅仅是用来约束,如果没有这个约束,所有在组件的属性中送过来的属性都会被接受。
单个根元素
这一章节讲了涉及多个元素的组件是如何组织的。
例如:
<h3>{{ title }}</h3>
<div v-html="content"></div>
如果模板涉及了多个元素,那么需要将这些元素放在一个根元素内,上面这个模板就涉及到两个元素,这个时候需要在外面再包裹一个元素:
<div class="blog-post">
<h3>{{ title }}</h3>
<div v-html="content"></div>
</div>
下面的例子涉及到如何设计传递的参数。
<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>
合理的设计应该是:
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-post>
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<div v-html="post.content"></div>
</div>
`
})
通过事件向父级组件发送消息
这段没想明白应该怎么去总结,完全照搬过来没有什么意义。
<button v-on:click="$emit('enlarge-text')">
Enlarge text
</button>
这个是孩子组件(位于父组件之内),可以使用$emit向父组件发送一个自定义的消息。
<blog-post
...
v-on:enlarge-text="postFontSize += 0.1"
></blog-post>
父组件使用v-on去监听这个事件。
使用事件抛出一个值
接着上面的例子,如果想给父组件发送消息的同时,传递参数,需要这样:
孩子组件:
<button v-on:click="$emit('enlarge-text', 0.1)">
Enlarge text
</button>
父组件:
<blog-post
...
v-on:enlarge-text="postFontSize += $event"
></blog-post>
这里第二个参数,可以是一个值,或者是一个方法
methods: {
onEnlargeText: function (enlargeAmount) {
this.postFontSize += enlargeAmount
}
}
好像不能是对象,这个还要确认一下。
在组件上使用 v-model
有一点含糊了,prop和v-model在这里有什么区别呢?这个部分讲的感觉又有点不清楚。
<input v-model="searchText">
等价于
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
用在自定义的组件上(上面是标准的HTML元素),则是
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
和上面大体接近,只是最后的$event有区别。
为了让它正常工作,这个组件内的
<input>
必须:
将其 value 特性绑定到一个名叫 value 的 prop 上
在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
写成代码之后是这样的:
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>
意思是:
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
这么写和
<custom-input v-model="searchText"></custom-input>
这么写是一个意思,组件里面都要这么写:
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
对event进行了一次转发。
通过插槽分发内容
这里讲的是如何把元素的内容传递给组件,叫做分发内容,使用<slot>
这样的关键字来接收。
<alert-box>
Something bad happened.
</alert-box>
上面是一个自定义组件,给这个组件直接传递内容,会得到不正确的结果,需要有能接收这个内容的东西,这个就叫插槽。这个地方感觉讲的不清楚,自己尝试了一下。
如上图,这里并没有显示出内容来,没有用于接收的东西。
改为:
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})
则:
这样才显示出来。
动态组件
这段又没看懂。
<div id="dynamic-component-demo" class="demo">
<button v-for="tab in tabs" v-bind:key="tab" class="dynamic-component-demo-tab-button" v-bind:class="{ 'dynamic-component-demo-tab-button-active': tab === currentTab }"
v-on:click="currentTab = tab">
{{ tab }}
</button>
<component v-bind:is="currentTabComponent" class="dynamic-component-demo-tab"></component>
</div>
<script>
Vue.component('tab-home', { template: '<div>Home component</div>' })
Vue.component('tab-posts', { template: '<div>Posts component</div>' })
Vue.component('tab-archive', { template: '<div>Archive component</div>' })
new Vue({
el: '#dynamic-component-demo',
data: {
currentTab: 'Home',
tabs: ['Home', 'Posts', 'Archive']
},
computed: {
currentTabComponent: function () {
return 'tab-' + this.currentTab.toLowerCase()
}
}
})
</script>
<style>
.dynamic-component-demo-tab-button {
padding: 6px 10px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border: 1px solid #ccc;
cursor: pointer;
background: #f0f0f0;
margin-bottom: -1px;
margin-right: -1px;
}
.dynamic-component-demo-tab-button:hover {
background: #e0e0e0;
}
.dynamic-component-demo-tab-button-active {
background: #e0e0e0;
}
.dynamic-component-demo-tab {
border: 1px solid #ccc;
padding: 10px;
}
</style>
解析 DOM 模板时的注意事项
这段和上面那段有关联,但是好像也是没写清楚,继续等待深度理解。
总结
断断续续,花了三天,终于大体看明白了(花了很多时间看这个slot,也把后面的关于slot的看了一遍,基本梳理清楚),感觉这一章节是Vue的核心内容,还需要不断完善这篇笔记。
参考
posted on 2018-10-25 18:14 chaiyu2002 阅读(88) 评论(0) 编辑 收藏 举报