vue 组件基础
2018-07-22 本文已影响34人
rainbowboy
基础示例
组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
组件的复用
你可以将组件进行任意次数的复用:
- data必须是个函数
当我们定义这个 <button-counter> 组件时,你可能会发现它的 data选项必须是一个函数,
因此每个实例可以维护一份被返回对象的独立的拷贝
通过prop
向子组件传递数据
Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。为了给博文组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中:
单个根元素
一个组件里,只能有一个根元素,负责会报错
通过事件向父组件发送消息
我们可以调用内建的 $emit
方法并传入事件的名字,来向父级组件触发一个事件。
这里需要注意的是:父类组件绑定的事件名大小写不敏感的,但是在子组件里发送消息时必须要使用全部小写的方式发送消息,否则无法成功发送消息。比如:父组件绑定事件v-on:myPlay="playGame",子组建立调用时就是:$emit("myplay"),或者父子组件的事件名都是带短线的写法也是可以的。
- 使用事件抛出一个值
可以使用 emit 的第二个参数来提供这个值。例如:emit("myplay","play football")。然后当在父级组件监听这个事件的时候,我们可以通过$event
访问到被抛出的这个值:
*组件上使用v-model
插槽分发内容
Vue 自定义的 <slot>
元素可以实现插槽分发内容
动态组件
你可以在这里查阅并体验完整的代码,或在这个版本了解绑定组件选项对象,而不是已注册组件名的示例。
示例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title>组件基础</title>
<script src="../static/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<!--组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 <button-counter>。
我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:
因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、
watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。-->
<button-counter></button-counter>
<br />
<!--组件的复用:
你可以将组件进行任意次数的复用:
注意当点击按钮时,每个组件都会各自独立维护它的 count。
因为你每用一次组件,就会有一个它的新实例被创建。-->
<button-counter></button-counter>
<button-counter></button-counter>
<!--data 必须是一个函数
当我们定义这个 <button-counter> 组件时,你可能会发现它的 data选项必须是一个函数,
因此每个实例可以维护一份被返回对象的独立的拷贝:-->
<!--组件的组织:
通常一个应用会以一棵嵌套的组件树的形式来组织:
例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。
为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和
局部注册。至此,我们的组件都只是通过 Vue.component 全局注册的:-->
<!--通过 Prop 向子组件传递数据-->
<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>
<!--
作者:zzhrainbow@163.com
时间:2018-07-22
描述:在一个典型的应用中,你可能在 data 里有一个博文的数组:
-->
<blog-post v-for="post in posts" v-bind:title="post.title" v-bind:key="post.id"></blog-post>
<!--通过事件向父级组件发送消息:
在我们开发 <blog-post> 组件时,它的一些功能可能要求我们和父级
组件进行沟通。例如我们可能会引入一个可访问性的功能来放大博文的字号,
同时让页面的其它部分保持默认的字号。在其父组件中,我们可以通过添加一个
postFontSize 数据属性来支持这个功能:-->
<div v-bind:style="{fontSize:postFontSize + 'em'}">
<blog-post-elements v-for="post in postElements" v-bind:post="post" v-bind:key="post.id" v-on:changeBigText="changeFontSize($event)">
</blog-post-elements>
</div>
<!--使用事件抛出一个值
有的时候用一个事件来抛出一个特定的值是非常有用的。例如我们可能想让 <blog-post>
组件决定它的文本要放大多少。这时可以使用 $emit 的第二个参数来提供这个值:-->
<!--通过插槽分发内容:
和 HTML 元素一样,我们经常需要向一个组件传递内容,像这样:
幸好,Vue 自定义的 <slot> 元素让这变得非常简单:-->
<alert-box>
Something bad happened.
</alert-box>
<!--动态组件:
可以通过 Vue 的 <component> 元素加一个特殊的 is 特性来实现:-->
<button v-for="tab in tabs" v-bind:key="tab" v-bind:class="['tab-button', { active: currentTab === tab }]" v-on:click="currentTab = tab">{{ tab }}</button>
<component v-bind:is="currentTabComponent" class="tab"></component>
</div>
<script type="text/javascript">
Vue.component("buttonCounter", {
data() {
return {
count: 0,
}
},
template: "<button v-on:click='count++'>you clicked me {{count}} times</button>"
})
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
Vue.component('blog-post-elements', {
props: ['post'],
template: '<div ><h3>{{ post.title }}</h3> <button v-on:click="enlargeText" > enlarge text </button> <div v-html="post.content" > </div></div>',
methods: {
enlargeText() {
this.$emit("changebigtext", 0.3) //注意这里的传送事件与父组件里监听的事件名字的区别
}
},
})
Vue.component('alert-box', {
template: "<div class='demo - alert - box '><strong>Error!</strong><slot></slot> </div>"
})
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>'
})
var vm = new Vue({
el: "#app",
data: {
posts: [{
id: 1,
title: "first blog",
},
{
id: 2,
title: "second blog",
},
{
id: 3,
title: "third blog",
},
],
postFontSize: 1,
postElements: [{
id: 2016,
content: "<p>1.为了变大数据</p>",
},
{
id: 2017,
content: "<p>2.第二条</p>",
},
{
id: 2018,
content: "<p>3.第三条来了</p>",
},
],
currentTab: 'Home',
tabs: ['Home', 'Posts', 'Archive']
},
methods: {
changeFontSize(changeValue) {
this.postFontSize += changeValue
}
},
computed: {
currentTabComponent() {
return "tab-" + this.currentTab.toLowerCase()
}
}
})
</script>
<style type="text/css">
.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;
}
.tab-button:hover {
background: lightgray;
}
.tab-button.active {
background: lightgray;
}
.tab {
border: 1px solid #ccc;
padding: 10px;
background: lightpink;
}
</style>
</body>
</html>
运行效果:

参考:
vue.js 组件基础