目录
- 使用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>
效果图如下