1. 自定义组件( 插件 )
案例: 封装一个 Loading 组件
Loading是用来做什么的?
基于用户体验
loading使用方式很多
- 第三方的ui库/组件库
- 自定义封装
- 过程:
- 创建一个目录文件夹,称之为Loading
- 在loading中创建一个叫做component目录,用来放模板
- 在Loading目录下创建一个index.js
import Vue from 'vue' import tpl from './component/index.html' const Loading = { // 自定义封装组件,这个loading对象中必须有一个关键key install () {//一定要用install方法 Vue.component( 'Loading', { template: tpl }) } } export default Loading
- 使用:
-
指令是用来操作DOM
-
指令的使用形式: 属性
-
自定义指令方式有两种:
- 全局注册指令
- Vue.directive( 指令的名称, 指令的配置项 )
- 局部注册指令
- directives: {
‘指令名称’: 指令的配置项
}
- directives: {
- 全局注册指令
-
研究:
- 指令的配置项提供了5个钩子函数
- 以及钩子函数中的参数
- console.log( ‘el’,el ) // el 指令绑定的元素
- console.log( ‘binding’,binding ) // 指令的详细信息
- console.log( ‘vnode’, vnode ) // 当前绑定元素的信息
- console.log( ‘oldVnode’,oldVnode ) // 上一个绑定元素的信息
-
案例: 打开网页,input自动获得焦点
<div id="app"> <div class="box"> <button @click = 'flag = false'> 点击 </button> <input type="text" v-if = "flag" v-focus.yyb v-model = "msg"> <input type="text" v-if = "flag" v-focus v-model = "msg"> </div> </div>
Vue.directive( 'focus',{//全局注册指令 bind ( el,binding,vnode,oldVnode ) { //调用一次,指令一绑定在元素身上就会触发 // console.log( 'bind focus' ) // console.log( 'el',el ) // el 指令绑定的元素 // console.log( 'binding',binding ) // 指令的详细信息 // console.log( 'vnode', vnode ) // 当前绑定元素的信息 // console.log( 'oldVnode',oldVnode ) // 上一个绑定元素的信息 // el.style.background = 'red' }, inserted ( el,binding,vnode,oldVnode ) { // 当前绑定的元素插入父节点时调用 el.focus() if( binding.modifiers.yyb ){ el.style.color = 'green' }else{ el.style.color = 'red' } console.log( binding ) console.log( 'inserted ' ) }, update ( el, binding, vnode, oldVnode ) { // 当前指令绑定的元素发生改变 console.log( 'update' ) console.log( 'el',el ) // el 指令绑定的元素 console.log( 'binding',binding ) // 指令的详细信息 console.log( 'vnode', vnode ) // 当前绑定元素的信息 console.log( 'oldVnode',oldVnode ) // 上一个绑定元素的信息 }, componentUpdated ( el,binding,vnode,oldVnode) { //当前绑定元素发生改变,或是子元素发生改变 console.log( 'componentUpdated' ) }, unbind ( el,binding,vnode,oldVnode) { // 组件销毁时触发 console.log( 'unbind' ) } }) new Vue({ el: '#app', data: { msg: 1000, flag: true }, directives: {//局部注册指令 'focus': { bind () { }, inserted () { }, update () { }, componentUpdated () { }, unbind () { } } } })
- v-on:click = ‘aa’
- v-on:yyb = ‘aa’
- v-on:before-enter: ‘’
- v-on:aa = ‘fn’
- 自定义事件
事件的发布
事件的订阅<div id="app"></div>
var vm = new Vue({ el: '#app' }) vm.$on(事件的名称,事件的回调) //事件的发布 vm.$on('aa',function(){ alert( 'aa' ) }) // 事件的订阅 // vm.$emit(事件的名称) vm.$emit( 'aa' )
- 自定义事件的使用形式
- 组件生命周期中发布事件,通过某一个事件处理程序调用
<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') }) } })
- 绑定在组件身上 , 通过 v-on 绑定,可以实现子父组件通信
-
父子组件通信:父组件将自己的数据传递给子组件
-
子组件把父组件的数据通过属性绑定的形式传递给自己,单项数据绑定
<Son :aa = "money"></Son>
-
子组件在自己的配置项中通过 props 来接收这个属性
Vue.component('Son',{ template: '#son', // props: ['aa'], props: { // 属性: 属性的数据类型 给数据做属性验证,验证数据类型 'aa': Number } })
- 这个属性可以直接向全局变量一样使用
<p> 我老爸给了我:{{ aa }} 钱 </p>
-
-
子父组件通信 :子组件将数据发送给父组件
-
方法1,自定义事件
- 流程:
- 父组件中定义一个数据,然后在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…) 来订阅这个自定义事件
Vue.component('Son', { template: '#son', data () { return { money:1000 } }, methods:{ give () { this.$emit('send',this.money)//子组件通过this.$emit来订阅这个自定义事件 } } })
-
方法2,父组件将一个方法直接通过单向数据绑定的形式传递给子组件,子组件通过props接收,然后直接使用
-
方法3,父组件可以将一个对象型的数据传递给子组件,子组件修改了这个数据,父组件也同样会修改
- 这个形式违反了单向数据流,用的少
-
-
非父子组件通信
- 使用ref链绑定
- ref不仅可以绑定组件,也可以绑定普通元素
<!-- 举例 --> <div id="app"> <Brother ref="brother"></Brother> <hr> <Sister ref="sister"></Sister> </div> <template id="brother"> <div> <h3>brother</h3> <button @click="give">传递数据</button> <p>brother的数据是:{{ money }}</p> </div> </template> <template id="sister"> <div> <h3>sister</h3> <p>sister的数据是:{{ money }}</p> </div> </template>
//非父子组件通信:通过ref链,ref链的绑定必须通过父组件来看 Vue.component ('Brother',{ template:'#brother', data () { return { money:1000 } }, methods:{ give (){ this.$parent.$refs.sister.money=this.money//通过父级找到子级 } } }) Vue.component ('Sister',{ template:'#sister', data (){ return { money:0 } } }) new Vue({ el: '#app', // mounted (){ // console.log(this) // } })
- 使用事件总线(bus总线)
<!-- 举例 --> <div id="app"> <Brother></Brother> <hr> <Sister></Sister> </div> <template id="brother"> <div> <h3>brother</h3> <button @click="give">传递</button> <p>brother的数据是:{{ money }}</p> </div> </template> <template id="sister"> <div> <h3>sister</h3> <p>sister的数据是:{{ money }}</p> </div> </template>
//非父子组件通信:事件总线,通过事件来做 // 事件的发布 $on(方法名称,回调函数) // 事件的订阅 $emit(方法名称) //通过new Vue开辟另外一个实例,再用这个实例上面的$on和$emit方法 var bus = new Vue() Vue.component('Brother', { template: '#brother', data() { return { money: 1000 } }, methods: { give() { bus.$emit('give',this.money)//通过参数的形式传递数据 } } }) Vue.component('Sister', {//自己管理自己的数据 template: '#sister', data() { return { money: 0 } }, mounted () {//组建一创建就要有这个数据 bus.$on('give', (val) => {//这里要用箭头函数,否则this会丢失 this.money += val }) } }) new Vue({ el: '#app', })
- 使用ref链绑定
-
多组件的状态共享 vuex( 目前不讲, 改天)
-
多级组件通信 ( $attr 扩展 )
-
vue-router ( 目前不讲, 改天)
-
在一个组件当中,自己的数据由自己管理