1、组件的概念
组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树
2、全局组件的注册(所有实例都能用)
注册一个全局组件语法格式如下:
- Vue.component(tagName, options)
tagName 为组件名,options 为配置选项。 - 注册后,我们可以使用以下方式来调用组件:
<tagName></tagName>
<div id="app">
app<runoob></runoob>
</div>
<div id="app1">
app1<runoob></runoob>
</div>
<script>
// 注册全局组件runoob
Vue.component('runoob', {
template: '<h1>自定义全局组件!</h1>'
});
// 创建Vue根实例
new Vue({
el: '#app'
});
new Vue({
el:'#app1'
})
</script>
3、局部组件的注册
- 我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用
<div id="app">
app<runoob></runoob>
</div>
<div id="app1">
app1<runoob></runoob>
</div>
<script>
let Child = {
template: '<h1>自定义组件!</h1>'
};
// 创建Vue根实例
new Vue({
el: '#app',
components: {
// <runoob> 将只在父模板可用
'runoob': Child
}
});
new Vue({
el:'app1'
})
</script>
4、父子组件通信(props)
- prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop": - 注意: prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
<div id="app">
<parent></parent>
</div>
<script>
let child = {
template: `<div><p>这是个子组件{{name}}</p></div>`,
// 声明 props
props: ["name"]
};
let parent = {
//模板
template: `<div>
<h1>这是个父组件</h1>
<child :name="username"></child>
</div>`,
//注册一个子组件
components: {
child: child
},
data() {
return {
username: "peiqi"
}
}
};
//创建Vue根实例
const app = new Vue({
el: "#app",
//注册一个局部组件parent
components: {
parent: parent
}
})
</script>
- 动态 Props
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
<div id="app">
<div>
<input v-model="parentMsg">
<br>
<child v-bind:message="parentMsg"></child>
</div>
</div>
<script>
// 注册
Vue.component('child', {
// 声明 props
props: ['message'],
// 同样也可以在 vm 实例中像 "this.message" 这样使用
template: '<span>{{ message }}</span>'
})
// 创建根实例
new Vue({
el: '#app',
data: {
parentMsg: '父组件内容'
}
})
</script>
- 以下实例中将 v-bind 指令将 todo 传到每一个重复的组件中:
<div id="app">
<ol>
<todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
</ol>
</div>
<script>
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
new Vue({
el: '#app',
data: {
sites: [
{ text: 'Runoob' },
{ text: 'Google' },
{ text: 'Taobao' }
]
}
})
</script>
5、子父组件通信
- 上面我们说过,props 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
- 那么想一下子父通信怎么实现呢?
机智如你发现:给子组件绑定事件,通过$emit将事件提交(可以携带参数),在父组件中绑定对应事件的处理函数就可以实现子父组件的通信了。
<div id="app">
<parent></parent>
</div>
<script>
// 子组件 提交一个事件 可以携带值
let child = {
template: `<div>
<p>这是个子组件</p>
<button @click="on_click">点我显示你银行卡余额</button>
</div>`,
methods: {
on_click: function () {
//提交一个事件 可以携带值
this.$emit("show_balance", this.balance)
}
},
data() {
return {
balance: 998,
}
}
};
let parent = {
template: `<div>
<h1>这是个父组件</h1>
<child @show_balance="my_func"></child>
<span>{{p_balance}}</span>
</div>`,
//注册一个子组件
components: {
child: child
},
data() {
return {
username: "peiqi",
p_balance: ""
}
},
methods: {
my_func: function (data) {
this.p_balance = data
}
}
};
//创建Vue根实例
const app = new Vue({
//制定作用域
el: "#app",
//注册一个局部组件
components: {
parent: parent
}
})
</script>
6、非父子组件通信
- 非父子组件的通信没有办法通过绑定事件来解决了,那就需要通过生成一个中间Vue实例来做父子组件通信的媒介,一个时间通过 Vue实例.on()去处理传来的事件就可以完成两个互不相干的组件之间的通信了。
- 只要思想不滑坡,方法总比问题多!!!
<div id="app">
<alex></alex>
<wenzhou></wenzhou>
</div>
<script>
//生成一个中间Vue实例用于数据传递
let Event = new Vue();
let alex = {
template: `<div>
<p>Alex</p>
//绑定事件
<button @click="on_click">点我给文周降薪</button>
</div>`,
methods: {
on_click: function () {
//提交事件、传递参数
Event.$emit("alex_said", this.money)
}
},
//必须是这种return的数据形式
data() {
return {
money: 10000,
}
}
};
let wenzhou = {
template: `<div>
<p>哪吒</p>
{{wz_money}}
</div>`,
// 加载结束后执行的
mounted() {
let that = this;
Event.$on("alex_said", function (data) {
that.wz_money = data;
console.log(this)
})
},
data() {
return {
wz_money: "",
}
}
};
//创建Vue根实例
const app = new Vue({
//制定作用域
el: "#app",
//注册两个局部组件
components: {
alex: alex,
wenzhou: wenzhou,
}
})
</script>
7、mixins重复代码封装,类似于django中的母板
<div id="app">
<popup></popup>
<tip></tip>
</div>
<script>
let base = {
methods: {
on_show: function () {
this.show = true
},
on_hide: function () {
this.show = false
}
},
data() {
return {
show: false
}
}
};
let popup = {
template: `<div>
<button @click="on_show">点我显示</button>
<button @click="on_hide">点我隐藏</button>
<p v-show="show">这是popup</p>
</div>`,
mixins: [base],
data() {
return {
show: true
}
}
};
let tip = {
template: `<div>
<button v-on="{mouseenter: on_show, mouseleave: on_hide}">鼠标移入提示信息</button>
<p v-show="show">这是一个提示信息</p>
</div>`,
mixins: [base]
};
const app = new Vue({
el: "#app",
components: {
popup: popup,
tip: tip,
}
})
</script>
8、slot插槽
<div id="app">
<test>
<div slot="title"> 这是一个标题</div>
<div slot="footer">这是底部</div>
</test>
</div>
<template id="panel-tpl">
<div>
<slot name="title">1</slot>
<hr>
<slot name="content">2</slot>
<hr>
<slot name="footer">3</slot>
</div>
</template>
<script>
let test = {
template: "#panel-tpl"
};
const app = new Vue({
el: "#app",
components: {
test: test
}
})
</script>