参考网址:
https://vue.docschina.org/v2/guide/components.html
大部分来自官网,一些是根据别人提的问题做的总结,
希望我把问题说明白了。
合起来的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="test">
<blog-post v-for="post in posts" v-bind:key="post.id" v-bind:post="post" ></blog-post>
</div>
</body>
<script>
Vue.component('blog-post',{
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<div v-html="post.content">
</div>
</div>
`,
data(){
return{}
}
})
var test = new Vue({
el:'#test',
data: {
posts:[
{id:1,title:'做梦',content:'是的'},
{id:2,title:'做梦',content:'是的'},
{id:3,title:'做梦',content:'是的'},
]
}
})
</script>
</html>
单个根元素
根元素也就是说在网页上作为根的元素,
一般<html></html>
这样的就是根元素。
在创建 <blog-post>
组件时,最终的模板中,不仅要包含标题:
<h3>{{ title }}</h3>
至少,还需要包含文章的内容:
<h3>{{ title }}</h3>
<div v-html="content"></div>
如果你试图在 template 模板中按照以上方式书写,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:
显示的时候用一个v-for循环来引用每个post项的id(同时也是键值)和内容——每个post对象,post具有若干属性
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-post>
Vue的组件定义:
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<div v-html="post.content"></div>
</div>
`
})
上面的示例,还有接下来的一些示例,都用到了 JavaScript 的 模板字面量(template literal),以便多行模板更加具备可读性。Internet Explorer (IE) 不支持此语法,因此如果你必须支持 IE,而又不想转译代码(例如,使用 Babel 或 TypeScript 进行转译),使用 新行转义(newline escapes) 替代模板字面量语法。
现在,不论何时为 post 对象添加一个新的属性,它都会自动地在 <blog-post>
内可用。
例如:
new Vue({
el: '#blog-post-demo',
data: {
posts: [
{ id: 1, title: '我的 Vue 旅程' , content: '内容一' },
{ id: 2, title: '用 Vue 写博客' , content: '内容2' },
{ id: 3, title: 'Vue 如此有趣' , content: '内容三' }
]
}
})
你还可以继续在content后面给post对象加别的属性。这样就不需要一对一地去v-bind
你需要的属性了,而可以直接在template里面引用post.xxxxx
,如下:
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<div v-html="post.content"></div>
</div>
`
使用 events 向父组件发送消息
在我们开发 <blog-post>
组件时,有些功能可能恰好与 props 相反,需要子组件反过来和父组件进行通信。例如,我们可能会决定添加能放大文章文本字号的辅助功能,而将页面的其余部分保留为默认大小:
在父组件中,我们可以通过在 data 中添加一个 postFontSize
属性来支持这种功能:
new Vue({
el: '#blog-posts-events-demo',
data: {
posts: [/* .省略.. */],
postFontSize: 1
}
})
以便控制博客组件 template
模板中,所有博客文章的字号大小:
<div id="blog-posts-events-demo">
<div :style="{ fontSize: postFontSize + 'em' }">
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-post>
</div>
</div>
现在,我们在每篇文章的内容前面添加一个可以加大文本字号的按钮:
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<button>
放大文本
</button>
<div v-html="post.content"></div>
</div>
`
})
现在的问题是,这里的 button 无法实现这个功能:
<button>
放大文本
</button>
当我们点击 button 时,我们需要和父组件通信,告知它加大所有文章的文本字号。幸运的是,Vue 实例为我们提供了一个自定义事件(custom event)
系统,来解决这个问题。想要向父组件发送事件,我们可以调用实例中内置的 $emit 方法,传递事件名称enlarge-text:
<button v-on:click="$emit('enlarge-text')">
放大文本
</button>
然后在我们的博客文章组件上,我们可以通过 v-on 监听这个事件enlarge-text,就如同我们使用原生 DOM 事件一样:
<blog-post
...
v-on:enlarge-text="postFontSize += 0.1"
></blog-post>
在 event 事件中发送一个值
有时,想在 event 事件中发送一个特定的值。例如,我们可能想要在 <blog-post>
组件自身内部,去控制放大文本字号的间隔。在这种情况下,我们可以使用 $emit
的第二个参数来提供字号间隔值:
<button v-on:click="$emit('enlarge-text', 0.1)">
放大文本
</button>
然后,当我们在父实例中监听这个事件时,我们可以通过 $event 来访问这次发送事件的值,不仅传送增加字体大小的控制enlarge-text,还要传送字号间隔值0.1:
<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
}
}