自定义组件
案例: 封装一个 Loading 组件
Loading是用来做什么的?
基于用户体验
- 第三方的ui库/组件库
- 自定义封装
- 过程:
- 创建一个目录文件夹,称之为Loading
- 在loading中创建一个叫做component目录,用来放模板
- 在Loading目录下创建一个index.js
~ import Vue from 'vue' import tpl from './component/index.html' const Loading = { // 自定义封装组件,这个loading对象中必须有一个关键key install () { Vue.component( 'Loading', { template: tpl }) } } export default Loading
自定义指令
- 指令是用来操作DOM
- 指令的使用形式: 属性
- 自定义指令方式有两种:
- 全局注册指令
Vue.directive( 指令的名称, 指令的配置项 ) - 局部注册指令
directives: {
‘指令名称’: 指令的配置项
}
- 全局注册指令
- 指令的配置项提供了5个钩子函数
-
bind ( el,binding,vnode,oldVnode){}//调用一次,指令一绑定在元素身上就会触发。
- el 指令绑定的元素
- binding 指令的详细信息
- vnode 当前绑定元素的信息
- oldVnode 上一个绑定元素的信息
-
inserted(el,binding,vnode,oldVnode){}//当前绑定的元素插入父节点时调用。
- el 指令绑定的元素
- binding 指令的详细信息
- vnode 当前绑定元素的信息
- oldVnode 上一个绑定元素的信息
-
update (el,binding,vnode,oldVnode){}//当前指令绑定的元素发生改变。
- el 指令绑定的元素
- binding 指令的详细信息
- vnode 当前绑定元素的信息
- oldVnode 上一个绑定元素的信息
-
componentUpdated(el,binding,vnode,oldVnode){}//当前绑定元素发生改变,或是子元素发生改变。
-
unbind (el,binding,vnode,oldVnode){}//组件销毁时触发。
- 案例:打开网页,input自动获得焦点
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
<style>
.box{
width: 300px;
height: 300px;
background: blue;
}
</style>
</head>
<body>
<div id="app">
<div class="box">
<button @click = 'flag = false'> 点击 </button>
<input type="text" v-if = "flag" v-focus.st v-model = "msg">
<input type="text" v-if = "flag" v-focus v-model = "msg">
</div>
</div>
</body>
<script>
//全局定义自定义指令
Vue.directives('focus', {
bind(el, binding, vnode, oldVnode) {
},
inserted(el, binding, vnode, oldVnode) {
el.focus()
if (binding.modifiers.yyb) {
el.style.color = 'green';
} else {
el.style.color = 'red';
}
},
update(el, binding, vnode, oldVnode) {
},
componentUpdated(el, binding, vnode, oldVnode) {
},
unbind(el, binding, vnode, oldVnode) {
}
})
new Vue({
el: '#app',
data: {
msg: 1000,
flag: true
},
//局部自定义指令
directives: {
'focus': {
bind() {
},
inserted() {
},
update() {
},
componentUpdated() {
},
unbind() {
}
}
}
})
</script>
自定义事件
v-on:aa = ‘fn’
- 自定义事件的使用形式
- 组件生命周期中发布事件,通过某一个事件处理程序调用
- 绑定在组件身上 ,通过 v-on 绑定
<div id="app">
<button @click = 'fn'> 点击 </button>
</div>
var vm = new Vue({
el: '#app',
methods: {
fn () {
this.$emit('aa')
}
},
mounted () {
this.$on('aa',function(){
alert('aa')
})
}
})
组件通信
父子组件通信
-
父子组件通信: 父组件将自己的数据传递给子组件
- 父组件将自己的数据通过属性绑定的形式传递给子组件
<Son :aa = "money"></Son>
- 子组件在自己的配置项中通过 props 来接收这个属性
Vue.component('Son',{ template: '#son', // props: ['aa'], props: { // 属性: 属性的数据类型 给数据做属性验证,验证数据类型 'aa': Number } })
- 这个属性可以直接向全局变量一样使用
<p>我老爸给了我:{{ aa }}钱</p>
Vue.component('Father',{ template: '#father', data () { return { money: '1000' } } }) Vue.component('Son',{ template: '#son', // props: ['aa'] //可以写数组也可以写对象,如果写对象,验证数据类型 props: { // 属性: 属性的数据类型 给数据做属性验证,验证数据类型 'aa': Number } }) new Vue({ el: '#app'
- 父组件将自己的数据通过属性绑定的形式传递给子组件
子父组件通信
- 自定义事件
- 流程
- 父组件中定义一个数据,然后在methods定义一个方法用来修改这个数据
Vue.component('Father',{ template: '#father', data () { return { num: 0 } }, methods: { add ( val ) { console.log('add') this.num += val } } })
- 父组件通过自定义事件的形式,将父组件的一个方法传递给子组件
<Son @aa = 'add'></Son>
- 子组件可以通过 this.$emit( 自定义事件名称,参数1,参数2…) 来订阅这个自定义事件
this.$emit('aa',this.money)
- 父组件中定义一个数据,然后在methods定义一个方法用来修改这个数据
-
父组件将一个方法直接通过单向数据绑定的形式传递给子组件,子组件通过props接收,然后直接使用
<div id="app"> <Father></Father> </div> <template id="father"> <div> <h3> 这里是father </h3> <p> 我这里有 {{ money }} 钱 </p> <hr> <Son :add = 'add'></Son> </div> </template> <template id="son"> <div> <h3> 这里是son </h3> <button @click = "add( money )"> give money </button> </div> </template> <script> Vue.component('Father', { template: '#father', data() { return { money: 0, } }, methods: { add(val) { this.money += val; } } }); Vue.component('Son', { template: '#son', data() { return { money: 1000 } }, props: ['add'], }) new Vue({ el: '#app', }) </script>
-
父组件可以将一个对象型的数据传递给子组件,子组件修改了这个数据,父组件也同样会修改
- 这个形式违反了单向数据流,用的少
非父子通信
- 非父子组件通信第一种形式:ref链绑定。ref不仅可以绑定组件,也可以绑定普通元素。
<div id="app">
<Brother ref = "brother"></Brother>
<hr>
<Sister ref = 'sister'></Sister>
<div ref = 'box'></div>
</div>
<template id="brother">
<div>
<h3> 这里是brother </h3>
<button @click = 'give'> give sister money </button>
</div>
</template>
<template id="sister">
<div>
<h3> 这里是sister </h3>
<p> 我有 {{ jk }} </p>
</div>
</template>
</body>
<script>
Vue.component('Brother',{
template: '#brother',
data () {
return {
money: 1000
}
},
methods: {
give () {
this.$parent.$refs.sister.jk = this.money
}
}
})
Vue.component('Sister',{
template: '#sister',
data () {
return {
jk: 0
}
}
})
new Vue({
el: '#app',
mounted () {
console.log('====================================');
console.log(this.$refs);
console.log('====================================');
}
})
</script>
- 非父子组件通信第二种形式: 事件总线
- 事件的发布: $on
- 事件的订阅: $emit
- 通过 new Vue 在得到另外一个实例
<div id="app">
<Brother></Brother>
<hr>
<Sister></Sister>
</div>
<template id="brother">
<div>
<h3> 这里是brother </h3>
<button @click = 'give'> give </button>
</div>
</template>
<template id="sister">
<div>
<h3> 这里是sister </h3>
<p> 弟弟给了我 {{ jk }} </p>
</div>
</template>
</body>
<script>
var bus = new Vue()
Vue.component('Brother',{
template: '#brother',
data () {
return {
money: 1000
}
},
methods: {
give () {
bus.$emit('aa',this.money)
}
}
})
Vue.component('Sister',{
template: '#sister',
data () {
return {
jk: 0
}
},
mounted () {
bus.$on('aa',( val ) => {
this.jk += val
})
}
})
new Vue({
el: '#app',
})
</script>