宝刀未老,Vue2组件化开发

421 阅读3分钟

这是我参与更文挑战的第 2 天,活动详情查看: 更文挑战

2021-06-02 Vue2 Vue2的组件化开发

宝刀未老,Vue2组件化开发

于总结这期知识点的时候,vue3其实已经比较成熟了,使用vue3开发项目,是真的丝滑般的顺畅~,但是在很多企业项目应用中仍然是vue2,只有少许的新项目才会采用vue3去开发,甚至很多的新项目依然采用vue2去开发,毕竟生态组件完善,所以讲vue2知识点的系列称为“宝刀未老”,但是啊技术领域就是这样,没有一直锋利的宝刀,只有一直不断的业务~,现在未老,但终会老去!有点伤感是吧!卷起来吧,少年。本系列不讲特别基础的东西,基础不行的去看vue2文档吧,我不想copy

1. Vue2中组件的传参方式

  • 非边界情况

    1. props
    2. $emit/$on
    3. event bus
    4. vuex
  • 边界情况

    1. $parent$children$root$refs(一般要配合$emit/$on)
    2. provide/inject
    3. $attrs 也就是当子组件没有声明props,而父组件有给子组件一个属性值,例如:<test-child :test="'我是子组件'"></test-child>,那么子组件要获取这个属性值就是通过this.$attrs.test去获取
    4. $listeners,理解了$attrs对应的是属性,其实$listener对应的就是方法

这里是重点说一下重要的几个一个是event bus一个是边界情况

1.1 event bus

也就是数据总线,其实有一个很简单的内部实现方法就是,你直接用Vue.prototype.$bus = new Vue();,为什么可以这样创建一个总线呢?可以简单的理解成,new Vue()就是最大的那个vue组件被实例化了,然后就拥有了$emit$on这两个方法属性

一般使用如下:

// main.js
Vue.prototype.$bus = new Vue();
// 组件A在$bus 上注册一个方法
this.$bus.$emit('testEmit','我坐公交来的')
// 组件B要$bus去监听组件A注册一个方法
created(){
    this.$bus.$on('testEmit',(value)=>{
        console.log( value ,'接受到了')
    })
}

通过上面的方式就能实现任何层级组件的一种通讯

1.2 $parent

其实用$parent实现数据通讯,和event bus有者异曲同工之妙,因为这个是取父实例,如果当前实例有的话

例如:

// 兄弟组件A
mounted(){
	this.$parent.$emit('sendMsg','我发送一个消息')
}
// 兄弟组件B
created(){
	this.$parent.$on('sendMsg',(value)=>{
		console.log(value,'我接受到兄弟a给我的消息了')
	})
}

1.3 $root

如果理解了event bus$parent其实这个也差不多,$root充当的角色和$bus$parent是差不多的,所以,在传递组件信息方面用法上区别不大

1.4 $refs

这个就$refs如果是绑定的vue组件,他就是vue的一个组件实例,就能拿到这个组件的实例就能拿到这个组件的方法,数据等等一些信息,具体的东西可以console.dir()打印一下看看,当然如果是绑定的是一个原生dom元素,那么就是拿到就是原生的dom元素。

1.3 $children

其实这个边界用的比上面的要少很多很多。这个可以拿到组件下子组件实例的元素组成的数组,很关键的一点是$children中的子元素成员并不保证顺序

1.5 provide/inject

跨层级传参

其实这个东西也挺好用的,祖先到子元素传值变得更加简单

具体用法看下面代码:

// 祖先元素
...
data(){
	return{
		reactive:{
			num:0
		}
	}
},
provide(){
    return{
        test:'注入',
        reactive:this.reactive
    }
}
...
// 子元素
...
inject:{
	// 类似于props
    testOne:{
        from:'test',
        default:{
            num:0
        }
    },
    reactive:{
    	from:'reactive'
    }
}
...

值得注意的是provide/inject本身是没有响应式的,那么怎么做到数据响应式变化呢,那就是provide去提供一个响应式的引用类型变量,引用类型里面的值改变,子元素inject到的这个引用数据也就响应式的,里面的值会同步改变

2. vue组件之v-model的实现

其实这部分很简单,只是因为我们通常是做业务,很少用到,

自定义组件的 v-model步骤:

  1. 在自定义组件中加上model属性,指定绑定的属性和要分发的事件名称
  2. 然后再该组件写上model指定的属性和分发的事件并完善,这个一个组件的v-model就完成了
...
model:{
    prop: 'show',
    event: 'change'
},
methods: {
    closeEvent(){
        this.$emit('change',false)
    }
}
...

3. vue的message实现思路

接下来就看一下message的实现,然后窥一斑见一豹。(最简单的方式就是参考element-ui里面的实现方式) 其实如果有想法可以先到Element官网里面看一下message的功能,这边就讲讲核心的东西

  1. 直接使用this.$message[type],就能调用
  2. message节点是插入到body上面的

第一个点解决很好解决,直接使用Vue.prototype.$message = message,只需要实现message这个函数即可

第二点怎么解决了,其实也很容易,先创建一个message的模板,然后使用Vue.extend创建一个“子类”比如叫instanceClass。参数是一个包含组件选项的对象,然后再使用const instance = new instanceClass.$mount()去获取这个子类的实例,然后通过这个实例的$el就能拿到这个实例的真实的dom元素,最后document.body.appendChild(instance.$el);

通过以上两步就完美的解决了实现message的核心步骤,其他细枝末叶就读者自己思考实现吧~