接前文
本来在 系列6尾部有说把 emitter.js中的混入函数拿出来讲一下,突然发现其实在 radio组件里面涉及不多,因此就单独根据 radio使用到的函数讲一下。
我模仿的代码都会放在该地址下,有兴趣看的同学可以点链接。
正文
首先还是说一下 混入 的概念吧。 混入从名字不难理解说是 将什么东西混入到目标当中,(其实它就是这么个意思)。
比如说我们有多个页面需要用到一个函数,通常情况下我们会把这个函数单独抽离出来,在需要的页面import即可,其实混入也是差不多的。 那么为什么要有 混入这个东西存在呢? 比如说你需要这个公有的函数,并且在这个函数中需要操作当前模块的数据怎么办?
举个场景吧。
在工作中有这么一个场景,我需要把 excel文件导入进页面,并且显示出来(前端引入并处理,不经过后端)。这时候引入文件需要动态生成表头,数据。如果使用 import我们需要在这个 import引入的函数里处理好数据然后将数据return回去,然后模块内置其他函数接收处理的结果并操作。
但是使用混入的话,我们只需要
data () {
return {
head: [],
value: []
}
},
methods: {
dealMethods () {...}
}
我们可以直接将需要的数据和方法通过混入的方式导入页面即可。 并且 混入的数据,方法和本页面数据方法产生冲突的时候,会以当前页面的数据为主,混入的冲突数据和方法会被覆盖掉,这就减少了冲突的风险。
我们看一下在 radio中混入的方法
dispatch(componentName, eventName, params) {
var parent = this.$parent || this.$root
var name = parent.$options.componentName
while (parent && (!name || name !== componentName)) {
parent = parent.$parent
if (parent) {
name = parent.$options.componentName
}
}
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params))
}
},
在radio不涉及到 form组件的情况下,触发的混入方法就是 dispatch
触发代码
model: {
get() {
// 如果是以el-radio-group包裹 则取group的value值
return this.isGroup ? this._radioGroup.value : this.value
},
set(val) {
console.warn(val)
if (this.isGroup) {
this.dispatch('ElTestRadioGroup', 'input', [val])
} else {
this.$emit('input', val)
}
this.$refs.radio && (this.$refs.radio.checked = this.model === this.label)
}
},
当我们点击某个 radio按钮的时候,如果radio位于radio-group中时,此时 this.isGroup为 true,则触发 dispatch函数。
dispatch会获取当前组件的父组件,并一直向上查询,直到没有父组件或者 父组件为ElTestRadioGroup(我的测试代码均在el后加test,官方的父组件为 ElRadioGroup), 如果找到,就触发 input事件,并通过 apply将参数带过去。
为什么使用apply,
因为这样参数是以数组形式传递过去, 使用call返回的是参数列表, 而 bind则绑定指定对象,并返回该函数, apply、call则会立即执行该函数。
radio-group源码
<template>
<div
class="el-radio-group"
role="radioGroup"
@keydown="handleKeyDown"
>
<slot></slot>
</div>
</template>
<script>
import Emitter from "@/plugins/mixins/emitter.js";
// 上下左右键码
const keyCode = Object.freeze({
LEFT: 37,
UP: 38,
RIGHT: 39,
DOWN: 40
});
export default {
name: "ElTestRadioGroup",
componentName: "ElTestRadioGroup",
// 集成自el-form的属性
inject: {
elFormItem: {
default: ''
}
},
mixins: [Emitter],
props: {
value: {},
size: String,
fill: String,
textColor: String,
disabled: Boolean
},
computed: {
_elFormItemSize() {
return (this.elFormItem || {}).elFormItemsSize;
},
radioGroupSize() {
return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
}
},
created() {
// 定义一个监听函数
this.$on("handleChange", value => {
this.$emit("change", value);
});
},
mounted() {
// 当radioGroup没有默认选项时,第一个可以选中Tab导航
const radios = this.$el.querySelectorAll("[type=radio]");
const firstLabel = this.$el.querySelectorAll("[role=radio]")[0];
if (![].some.call(radios, radio => radio.checked) && firstLabel) {
firstLabel.tabIndex = 0;
console.warn(1)
}
},
methods: {
// 上下左右按键 触发radio
handleKeyDown (e) {
// 获取触发该事件的节点
const target = e.target;
// 判断是否是原生input节点
const className = target.nodeName === 'INPUT' ? '[type=radio]' : '[role=radio]'
const radios = this.$el.querySelectorAll(className);
const length = radios.length;
const index = [].indexOf.call(radios, target)
const roleRadios = this.$el.querySelectorAll('[role=radio]')
switch (e.keyCode) {
case keyCode.LEFT:
case keyCode.UP:
// (删除这两个事件好像没什么变化)
// 阻止事件的传播 阻止该事件配分派到其他节点上
e.stopPropagation();
//如果此事件没有被显式处理,那么它默认的动作也不要做(因为默认是要做的)。此事件还是继续传播,除非碰到事件侦听器调用stopPropagation() 或stopImmediatePropagation(),才停止传播
e.preventDefault();
if (index === 0) {
roleRadios[length - 1].click();
roleRadios[length - 1].focus();
} else {
roleRadios[index - 1].click();
roleRadios[index - 1].focus();
}
break;
case keyCode.RIGHT:
case keyCode.DOWN:
if (index === (length - 1)) {
e.stopPropagation();
e.preventDefault();
roleRadios[0].click();
roleRadios[0].focus();
} else {
roleRadios[index + 1].click();
roleRadios[index + 1].focus();
}
break;
default:
break;
}
}
},
watch: {
value () {
this.dispatch('ElformItem', 'el.form.change', [this.value])
}
}
};
</script>
关于radio-group组件没有什么其他可以讲解的,在这里简单放出来,大家可以看一看。
总结
感觉这块没什么值得太大注意的 ,混入还是值得一学的。