目录
- 使用render封装一个select组件
- vue另类封装--render函数封装
- 先看看文件的结构
- render函数封装
使用render封装一个select组件
父组件
value - {{ value }} ; value2 - {{ value2 }} | |
<!-- disabled clearable --> | |
<Select v-model="value" :option-data="optionData" placeholder="请选择" clearable /> | |
<Select v-model="value2" :option-data="optionData" /> | |
value: '', // 默认值为空字符串 | |
value2: 'area1', | |
optionData: [ | |
{ label: '区域1', value: 'area1' }, | |
{ label: '区域2', value: 'area2' } | |
], |
Select.vue
<script> | |
export default { | |
name: 'Select', | |
props: { | |
value: { | |
default: '', | |
type: [String, Number] | |
}, | |
optionData: { | |
default: () => { | |
return [] | |
}, | |
type: Array | |
} | |
}, | |
computed: { | |
newValue: { | |
get({ value }) { | |
return value | |
}, | |
set(val) { | |
this.$emit('input', val) | |
} | |
} | |
}, | |
methods: { | |
onChangeHandle(val) { | |
this.newValue = val | |
} | |
}, | |
render(createElement) { | |
return createElement( | |
// 标签 | |
'el-select', | |
// 相关属性参数 | |
{ | |
// html 相关的属性 placeholder id 等 | |
attrs: { | |
...this.$attrs // ( { placeholder:请输入 } ) | |
}, | |
// props相关的 | |
props: { | |
value: this.newValue | |
}, | |
// 事件相关 | |
on: { | |
change: this.onChangeHandle | |
} | |
}, | |
this.optionData && this.optionData.map(option => { | |
return createElement( | |
'el-option', | |
{ | |
props: { | |
label: option.label, | |
value: option.value | |
} | |
} | |
) | |
}) | |
) | |
} | |
} | |
</script> |
效果
vue另类封装--render函数封装
在讲解render函数封装前,扩展一下组件自动全局注册的方法
先看看文件的结构
接下来就是注册代码(即lib下的index.js代码)
export default { | |
install(Vue) { | |
// 读取components文件夹下的文件 | |
// const req = require.context('路径','是否读取子文件夹','正则匹配') | |
// req是一个函数,该函数有三个属性分别是resolve、keys、id | |
// 下面进行详细说明这三个属性 | |
const req = require.context("@/components", false, /\.vue$/); | |
//拿到读取文件的路径 | |
//导入处理 | |
req.keys().forEach((item) => { | |
const com = req(item).default; | |
// 全局注册组件 | |
Vue.component(com.name, com); | |
}); | |
}, | |
}; |
接下来我们在App文件直接使用components下的组件
<template> | |
<div> | |
<myA></myA> | |
<myB></myB> | |
</div> | |
</template> | |
<script> | |
export default { | |
name: "", | |
data() { | |
return { | |
flag: false, | |
}; | |
}, | |
computed: {}, | |
methods: {}, | |
}; | |
</script> | |
<style lang="less" scoped></style> |
resolve
:它是一个函数,接收一个参数(这个参数是匹配文件的相对路径),返回值是匹配文件相对于项目的路径keys
:它也是一个函数,返回的是匹配成功文件的相对路径(不包括文件名称)id
:返回的是一个字符串,匹配的文件夹的路径()、匹配规则等
render函数封装
下面封装以面包屑为例
在a.vue下定义组件
<template> | |
<span> | |
<router-link v-if="to" :to="to"> | |
<slot /> | |
</router-link> | |
<span v-else> | |
<slot /> | |
</span> | |
</span> | |
</template> | |
<script> | |
export default { | |
name: "BreadcrumbItem", | |
props: { | |
to: { | |
type: [Object, String], | |
default: "", | |
}, | |
}, | |
}; | |
</script> |
在b组件进行封装
<script> | |
export default { | |
name: "Breadcrumb", | |
// 开启函数组件模式,它内部的东西不是响应式,并且没有生命周期 | |
functional: true, | |
render: (h, context) => { | |
//创建数组接收虚拟节点 | |
const vnodeArr = []; | |
context.slots().default.forEach((item, index, arr) => { | |
// 将处箭头外的虚拟dom存储起来 | |
vnodeArr.push(item); | |
// 判断是不是最后一项,是最后一项就不要加箭头 | |
if (arr.length - 1 !== index) { | |
// 加上箭头虚拟节点 | |
vnodeArr.push(h("i", { class: "el-icon-arrow-right" })); | |
} | |
}); | |
// render作用:它会return一个虚拟dom,return什么就渲染相应的实体Dom | |
// h:创建虚拟DOM,有三个参数 参数一:标签/组件 参数二:虚拟dom配置 参数三:虚拟dom/子节点 | |
// h(标签名/组件,{虚拟dom配置},子集:也是虚拟dom节点信息支持字符串与数组) | |
// 进行渲染,h第三个参数可以为数组 | |
return h("span", {}, vnodeArr); | |
}, | |
}; | |
</script> |
App组件运用
<template> | |
<div> | |
<Breadcrumb> | |
<BreadcrumbItem to="/">首页</BreadcrumbItem> | |
<BreadcrumbItem>活动列表</BreadcrumbItem> | |
<BreadcrumbItem>活动管理</BreadcrumbItem> | |
<BreadcrumbItem>活动详情</BreadcrumbItem> | |
</Breadcrumb> | |
</div> | |
</template> | |
<script> | |
export default { | |
name: "", | |
data() { | |
return { | |
flag: false, | |
}; | |
}, | |
computed: {}, | |
methods: {}, | |
}; | |
</script> | |
<style lang="less" scoped></style> |
效果图如下