1. 全局组件
<div id="app">
<button-counter></button-counter>
</div>
Vue.component("button-counter", {
data: function(){
return{
count: 0
}
},
template: "<button @click='handle'>点击了{{count}}次</button>",
methods:{
handle:function(){
this.count+=2;
}
}
});
var vm = new Vue({
el:"#app"
});
可以重用,子组件之间的数据都是独立的
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
2.局部组件
<div id="app">
<hello-world></hello-world>
<hello-a></hello-a>
<hello-b></hello-b>
</div>
<script>
var HelloWorld = {
data: function() {
return {
msg:"HelloWorld"
}
},
template:"<div>{{msg}}</div>"
};
var HelloA = {
data: function() {
return {
msg:"HelloA"
}
},
template:"<div>{{msg}}</div>"
};
var WorldB = {
data: function() {
return {
msg:"WorldB"
}
},
template:"<div>{{msg}}</div>"
};
var vm = new Vue({
el:"#app",
data:{
},
components: {
"hello-world": HelloWorld,
"hello-a": HelloA,
"hello-b": WorldB,
}
});
</script>
局部组件只能在注册他的父组件中使用,在其子组件中不可用
3.组件注册注意事项:
- data必须是一个函数
使用函数会形成一个闭包的环境,保证每一个组件都拥有独立的数据 - 组件模板内容必须是单个根元素
错误示范
template: "<button @click='handle'>点击了{{count}}次</button><button>又是一个按钮</button>",
解决方法:外部包一个div
template: "<div><button @click='handle'>点击了{{count}}次</button><button>又是一个按钮</button></div>",
单个根元素,每个组件必须只有一个根元素,否则后台会报错, 若要添加多个元素,则需要有一个根元素将子元素进行包裹,template里面用到的所有属性都需要在props数组内进行声明才可以进行使用,同时需要在使用组件的时候进行传值才可以, 否则该值会显示为undefined
,使用了 JavaScript 的模板字符串来让多行的模板更易读
<div id="app">
<blog-post :key="post.id" v-for="post in posts" :post="post"></blog-post>
</div>
<script>
Vue.component("blog-post", {
props: ["post"],
template: `
<div class="blog-post">
<h3>{{post.title}}</h3>
<div v-html="post.content"></div>
</div>
`
});
var vm = new Vue({
el:"#app",
data:{
posts:[
{id: 1, title: "My journey with Vue", content: "1234"},
{id: 2, title: 'Blogging with Vue', content: "1234"},
{id: 3, title: 'Why Vue is so fun', content: "1234" }
]
}
});
</script>
- 组件模板内容可以是模板字符串
template: `
<div>
<button @click='handle'>点击了{{count}}次</button>
<button>模板字符串的方式</button>
</div>
`
- 组件命名方式
- kebab-case (短横线分隔命名)
button-counter
- camelCase (驼峰命名法)
HelloWorld
*如果使用驼峰式命名组件,那么在使用组件的时候,只能在字符串模板中用驼峰的方式使用组件,但是在普通的标签的模板中,必须使用短横线的方式使用组件,或者把所有的大写字母转成小写加短横线hello-world
组件基础
1.父组件向子组件传递数据
- 通过
Props
父组件向子组件传递数据
在父组件中,直接通过属性的方式传递给子组件:title="来自父组件的值"
Props
接收父组件传过来的数据,是一个数组:props: ["title"],
静态绑定:
<div id="app">
<blog-post title="来自父组件的值"></blog-post>
</div>
<script>
Vue.component("blog-post", {
data () {
return {
msg:"子组件本身的数据"
}
},
props: ["title"],
template: "<h3>{{msg + '--' + title}}</h3>"
});
var vm = new Vue({
el:"#app"
});
</script>
v-bind
动态绑定属性值:pTitle
要在父组件中定义
<div id="app">
<blog-post :title="pTitle"></blog-post>
</div>
<script>
Vue.component("blog-post", {
data () {
return {
msg:"子组件本身的数据"
}
},
props: ["title"],
template: "<h3>{{msg + '--' + title}}</h3>"
});
var vm = new Vue({
el:"#app",
data:{
pTitle:"12345"
}
});
</script>
注意*:使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名
js中:驼峰命名法
Vue.component('blog-post', {
// 在 JavaScript 中是 camelCase 的
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
html中:短横线分隔命名
<!-- 在 HTML 中是 kebab-case 的 -->
<blog-post post-title="hello!"></blog-post>
到这里,我们只看到了以字符串数组形式列出的 prop:
还有其他四种
(1)
poros
属性值内容为数字
:tai="30"
属性值通过v-bind
绑定则,30
的typeof
为number
<div id="app">
<alert-box :dong="90" :tai="30"></alert-box>
</div>
<script>
Vue.component('alert-box', {
props:["dong", "tai"],
template: `
<div>
<strong>{{dong}}</strong>
<input :value="tai+12"></input>
</div>
`
})
var vm = new Vue({
el: '#app'
})
</script>
若tai="30"
,直接绑定,则30
的typeof
为string
,将做字符串拼接
<div id="app">
<alert-box :dong="90" tai="30"></alert-box>
</div>
(1)
poros
属性值内容为布尔值
设置按钮为不可按:disabled="true"
<div id="app">
<alert-box :dong="true" :tai="30"></alert-box>
</div>
<script>
Vue.component('alert-box', {
props:["dong", "tai"],
template: `
<div>
<button :disabled="dong">{{tai}}</button>
</div>
`
})
var vm = new Vue({
el: '#app'
})
</script>
与数字相似,若以v-bind
绑定,则为布尔值,若直接绑定,则"true"为字符串
(1)
poros
属性值内容为数组
<div id="app">
<alert-box :list="list"></alert-box>
</div>
<script>
Vue.component('alert-box', {
props:["list"],
template: `
<ul>
<li :key="index" v-for="(item, index) in list">{{item}}</li>
</ul>
`
})
var vm = new Vue({
el: '#app',
data:{
list:["banbana", "orange", "pear"]
}
})
</script>
(1)
poros
属性值内容为对象
<div id="app">
<alert-box :list="list"></alert-box>
</div>
<script>
Vue.component('alert-box', {
props:["list"],
template: `
<div>
<h1 :key="index" v-for="(item, index) in list">{{item.name + "---" + item.age}}</h1>
</div>
`
})
var vm = new Vue({
el: '#app',
data:{
list:[{
name:"ming",
age:20
},{
name:"hong",
age:10
}]
}
})
</script>
1.子组件向父组件传值–基本用法$emit
方法
props传递数据原则:单向数据流
因此子组件通过自定义事件的方式传递信息
- 子组件通过自定义事件向父组件传递信息
<button @click="$emit('enlarge-text')">Enlarge text</button>
- 父组件监听子组件的事件
<blog-post @enlarge-text="postFontSize += 5"></blog-post>
添加一个按钮来放大字号
<div id="app">
<div :style="{fontSize: postFontSize + 'px'}">
<blog-post :key="post.id" v-for="post in posts" :post="post" @enlarge-text="handle"></blog-post>
</div>
</div>
<script>
Vue.component("blog-post", {
props: ["post"],
template: `
<div class="blog-post">
<h3>{{post.title}}</h3>
<div v-html="post.content"></div>
<button @click="$emit('enlarge-text')">Enlarge text</button>
</div>
`
});
var vm = new Vue({
el:"#app",
data:{
posts:[
{id: 1, title: "My journey with Vue", content: "1234"},
{id: 2, title: 'Blogging with Vue', content: "1234"},
{id: 3, title: 'Why Vue is so fun', content: "1234" }
],
postFontSize: 10
},
methods: {
handle: function(){
this.postFontSize += 5;
}
}
},
);
</script>
使用事件抛出一个值$emit('enlarge-text', 5)
$event
例如我们可能想让 组件决定它的文本要放大多少。这时可以使用 $emit 的第二个参数来提供这个值
<div id="app">
<div :style="{fontSize: postFontSize + 'px'}">
<blog-post :key="post.id" v-for="post in posts" :post="post" @enlarge-text="postFontSize += $event"></blog-post>
</div>
</div>
<script>
Vue.component("blog-post", {
props: ["post"],
template: `
<div class="blog-post">
<h3>{{post.title}}</h3>
<div v-html="post.content"></div>
<button @click="$emit('enlarge-text', 1)">Enlarge text</button>
</div>
`
});
var vm = new Vue({
el:"#app",
data:{
posts:[
{id: 1, title: "My journey with Vue", content: "1234"},
{id: 2, title: 'Blogging with Vue', content: "1234"},
{id: 3, title: 'Why Vue is so fun', content: "1234" }
],
postFontSize: 30
}
});
</script>
或者,如果这个事件处理函数是一个方法,将$event
作为函数的参数传递过来
<div id="app">
<div :style="{fontSize: postFontSize + 'px'}">
<blog-post :key="post.id" v-for="post in posts" :post="post" @enlarge-text="handle($event)"></blog-post>
</div>
</div>
<script>
Vue.component("blog-post", {
props: ["post"],
template: `
<div class="blog-post">
<h3>{{post.title}}</h3>
<div v-html="post.content"></div>
<button @click="$emit('enlarge-text',1)">Enlarge text</button>
</div>
`
});
var vm = new Vue({
el:"#app",
data:{
posts:[
{id: 1, title: "My journey with Vue", content: "1234"},
{id: 2, title: 'Blogging with Vue', content: "1234"},
{id: 3, title: 'Why Vue is so fun', content: "1234" }
],
postFontSize: 10
},
methods: {
handle: function(val){
this.postFontSize += val
}
}
},
);
</script>
也可以省略不写,那么这个值将会作为第一个参数传入这个方法
@enlarge-text="handle"
插槽
通过插槽分发内容
<div id="app">
<alert-box>我在最后</alert-box>
</div>
<script>
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<h1>我在这儿</h1>
<slot></slot>
</div>
`
})
var vm = new Vue({
el: '#app'
})
</script>