Vue基础篇--8组件基础 component
Posted xujunkai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue基础篇--8组件基础 component相关的知识,希望对你有一定的参考价值。
Vue基础篇--8组件基础 component
1.简单示例
<div id='components1'>
<button-conter></button-conter>
</div>
<script>
// 定义一个名为button-conter组件
Vue.component("button-conter",{
data:function () {
return {
count:0
}
},
template:`<button v-on:click="count++">You clicked me {{count}}</button>`
});
// 创建一个根实例
new Vue({el:"#components1"})
</script>
- 组件是可以复用的,这样你在
id=‘components1‘
的作用域中再定义<button-conter></button-conter>
也是可以的,并且它们彼此之间互不影响。 - 因为组件是可复用的 Vue 实例,所以它们与
new Vue
接收相同的选项,例如data
、computed
、watch
、methods
以及生命周期钩子等。仅有的例外是像el
这样根实例特有的选项。
2.组件的复用
- 你可以将组件进行任意次数的复用:
<div id="components-demo">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
注意: 当点击按钮时,每个组件都会各自独立维护它的 count
。因为你每用一次组件,就会有一个它的新实例被创建。
data必须是一个函数
- 当我们定义这个 `
组件时,你可能会发现它的
data` 并不是像这样直接提供一个对象:
data: {
count: 0
}
取而代之的是,一个组件的 data
选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
data: function () {
return {
count: 0
}
}
3.组件的组织
通常一个应用会以一颗嵌套的组件树的形式来组织
例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。
为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。至此,我们的组件都只是通过
Vue.component
全局注册的:Vue.component('my-component-name', { // ... options ... })
全局注册的组件可以用在其被注册之后的任何 (通过
new Vue
) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。到目前为止,关于组件注册你需要了解的就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把组件注册读完。
4.通过 Prop 向子组件传递数据
- Prop 是你可以在组件上注册的一些自定义 attribute。当一个值传递给一个 prop attribute 的时候,它就变成了那个组件实例的一个属性。为了给博文组件传递一个标题,我们可以用一个
props
选项将其包含在该组件可接受的 prop 列表中:
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data
中的值一样。
一个 prop 被注册之后,你就可以像这样把数据作为一个自定义 attribute 传递进来:
<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>
然而在一个典型应用中,你可能在data
里有一个博文数组:
<div id='components1'>
<button-conter></button-conter>
<blog-post v-for="post in posts"
v-bind:title="post.title"
v-bind:key="post.id"
></blog-post>
</div>
// 定义一个名为button-conter组件
Vue.component("button-conter",{
data:function () {
return {
count:0,
}
},
template:`<button v-on:click="count++">You clicked me {{count}}</button>`
});
Vue.component("blog-post",{
props:['title'],
template:`<h3>{{title}}</h3>`
})
// 创建一个根实例
new Vue({el:"#components1",
data:{
posts:[
{id:1,title:"My journey with Vue"},
{id:2,title:"Blogging with Vue"},
{id:3,title:"Why Vue is so fun"},
]
}
})
如上所示,你会发现我们可以使用 v-bind
来动态传递 prop。这在你一开始不清楚要渲染的具体内容,比如从一个 API 获取博文列表的时候,是非常有用的。
5.单个根元素
当构建一个
<blog-post>
组件时,你的模板最终会包含的东西远不止一个标题:最最起码,你会包含这篇博文的正文:
<h3>{{ title }}</h3>
<div v-html="content"></div>
然而如果你在模板中尝试这样写,Vue 会显示一个错误,并解释道 every component must have a single root element (每个组件必须只有一个根元素)。你可以将模板的内容包裹在一个父元素内,来修复这个问题,例如:
<div class="blog-post">
<h3>{{ title }}</h3>
<div v-html="content"></div>
</div>
看起来当组件变得越来越复杂的时候,我们的博文不只需要标题和内容,还需要发布日期、评论等等。为每个相关的信息定义一个 prop 会变得很麻烦:
<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>
组件了,让它变成接受一个单独的 post prop:
<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>
`
})
上述的这个和一些接下来的示例使用了 javascript 的模板字符串来让多行的模板更易读。它们在 IE 下并没有被支持,所以如果你需要在不 (经过 Babel 或 TypeScript 之类的工具) 编译的情况下支持 IE,请使用折行转义字符取而代之。
现在,不论何时为 post
对象添加一个新的属性,它都会自动地在 <blog-post>
内可用。
6.监听子组件事件
在我们开发
<blog-post>
组件时,它内部一些功能要求我们和父级组件进行沟通。比如在父组件定义字体大小,子组件中 引入一个辅助功能来放大博文的字号 ,同时页面其他字号保持默认示例:
<div id='components1'> <!--在父组件中,我们添加一个postFontSize数据属性来支持这个功能--> <!--通过 v-on:enlarge-text="postFontSize += 0.1" 监听器,父级组件就会接收该事件并更新 postFontSize 的值--> <div :style="{fontSize:postFontSize + 'em'}"> <blog-post v-for="post in posts" v-bind:post="post" v-bind:key="post.id" v-on:enlarge-text="postFontSize += 0.1" ></blog-post> </div> </div>
Vue.component("blog-post",{ props:['post'], // 每篇博文正文之前添加一个按钮来放大字号 // 同时子组件调用内建$emit方法传入事件名称 template:`<div class="blog-post"> <h3>{{post.title}}</h3> <button v-on:click="$emit('enlarge-text')">Enlarge text</button> <div v-html="post.content"></div> </div>` }) // 创建一个根实例 new Vue({el:"#components1", data:{ posts:[ {id:1,title:"My journey with Vue",content:"<span>文章1</span>"}, {id:2,title:"Blogging with Vue",content:"<span>文章2</span>"}, {id:3,title:"Why Vue is so fun",content:"<span>文章3</span>"}, ], // 定义默认字体大小 postFontSize:1 } })
使用事件抛出一个值
例如我们想让
<blog-post>
组件决定它的文本要放大多少,可以通过使用$emit
第二个参数提供这个值<!--子组件定义传入放大的大小--> <button v-on:click="$emit('enlarge-text', 0.1)"> Enlarge text </button>
然后当父组件监听这个事件时候,我们通过
$event
访问抛出这个值:<blog-post ... v-on:enlarge-text="postFontSize += $event" ></blog-post>
又或用函数去处理这个事件:
<blog-post ... v-on:enlarge-text="onEnlargeText" ></blog-post>
// 那么这个值将会作为第一个参数传入这个方法 methods: { onEnlargeText: function (enlargeAmount) { this.postFontSize += enlargeAmount } }
在组件上使用v-model
自定义事件也可以用于创建支持
v-model
的自定义输入组件。<input v-model="searchText">
等价于
<input v-bind:value="searchText" v-on:input="searchText = $event.target.value" >
当用在组件上时,
v-model
则会这样:
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
为了让它正常工作,这个组件内的 `` 必须:
- 将其
value
attribute 绑定到一个名叫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>
7.通过插槽分发内容
- 和 HTML 元素一样,我们经常需要向一个组件传递内容,像这样:
<div id="demo">
<alert-box>
Something bad happened
</alert-box>
</div>
Vue.component("alert-box",{
template:`
<div class="demo-alert-box">
你好啊!
</div>
`
});
new Vue({el:"#demo"})
我们定义
<alert-box>
内的内容并没有打印出来,此时你只需要加入<slot></slot>
,这样内容都会打印出来。Vue.component("alert-box",{ template:` <div class="demo-alert-box"> 你好啊! <slot></slot> </div> ` }); new Vue({el:"#demo"})
8.动态组件
<div id="app">
<button @click="change">切换</button>
<component :is="type"></component>
</div>
Vue.component("One",{
template:"<span>One</span>"
});
Vue.component("Two",{
template:"<span>Two</span>"
});
new Vue({
el:"#app",
data:{
type:"One"
},
methods:{
change:function () {
this.type = (this.type === "One"?"Two":"One")
}
}
})
9.解析 DOM 模板时的注意事项
有些 HTML 元素,诸如
、
、和
,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如、 和
,只能出现在其它某些特定的元素内部。这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:
<table>
<blog-post-row></blog-post-row>
</table>
这个自定义组件 <blog-post-row>
会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is
attribute 给了我们一个变通的办法:
<table>
<tr is="blog-post-row"></tr>
</table>
参照文献:Vue.js组件基础
以上是关于Vue基础篇--8组件基础 component的主要内容,如果未能解决你的问题,请参考以下文章