从零开始解说vue中动态组件的创建和使用

微信扫一扫,分享到朋友圈

从零开始解说vue中动态组件的创建和使用
  1. 逻辑: 用户手动选择加入那些组件
  2. 方式:通过element ui tree组件复选框来选择,加载哪个组件

1.在html页面构建

加入keep-alive是保持这些组件的状态,以避免反复重渲染导致的性能问题

el-tree(:data="treeData"
ref="tree"
class="filter-tree"
show-checkbox
node-key="menuId"
@check="handleCheck"
:props="defaultProps")
keep-alive(v-for="(item, index) in compArr" :key="index")
component(:is="addComponents(item)"
@value-begin="getBegin"
@value-updated="getUpdate")
复制代码

2. 导入组件

// 导入组件
import overView from './report_overview/index'
import transparent from './report_transparent/index'
import reliable from './report_reliable/index'
复制代码

3. 定义组件

// 定义组件
const components = {
overView,
transparent,
reliable,
}
复制代码

4. 关联组件到固定id

唯一的id,可以用来加载id对应的组件

// 关联组件,这里是把treeData里面定义的menuId和组件相关联
const componentsView = {
'1': 'overView',
'2': 'reliable',
'3': 'transparent',
}
复制代码

5. 创建数据源,选择节点,加载节点对应组件

  • 逻辑:
  • 第一步,点击tree组件,可以知道选择的目录
  • 第二步,把目录和组件相关联
  • 第三步,根据这个目录,去寻找对应的组件来渲染
/**
* 选择节点,加载对应组件
* @param data
*/
handleCheck(e, a) {
console.log('一个', e, a);
// 选择节点
// 1. 添加或者删除节点对应的组件
// 2. a.checkedKeys是一个数组,对应当前选择的节点,所以点击的是时候根据a.checkedKeys,来添加对应的组件
this.compArr = []
// 处理只有id,但没有关联组件的节点
a.checkedKeys.map((item, index) => {
if (!componentsView[item]) {
this.$message({
message: '当前页面未添加对应组件,请联系管理员',
type: 'warning'
});
// 从数组取消当前复选框对应的id
a.checkedKeys.splice(index, 1)
}
})
// 按tree组件的选择增加对应的组件名称到数组
a.checkedKeys.map((item) => {
this.compArr.push({menuId: item, componentName: componentsView[item]})
})
// 按当前路径赋值到tree组件,当删除某一个复选框后,需要手动对当前tree节点赋值,不然不刷新
this.$refs.tree.setCheckedKeys(a.checkedKeys)
},
复制代码

动态组件component需要用的组件数据

/**
* 返回需要渲染的组件
* @param item
* @returns {*}
*/
addComponents(item){
return components[item.componentName]
},
复制代码

6. 根据组件内接口返回,来确认当前组件是否已经完成加载

在子组件内调用接口,这里的menuId是手动写死的,增加一个页面id就自增1,这个值完全可以由父组件传入

async getData() {
let api = '/'
let requestData = {}
// 进入接口初始化为未加载状态,把组件状态广播至父组件
this.loading = true
this.$emit('value-begin', {menuId: "00", flag: false})
let res = await this.$Http.axiosPost(api, requestData)
if (res.code === 200) {
this.loading = false
// 获取返回数据后,把加载成功的状态,广播至父组件
this.$emit('value-updated', {menuId: "00", flag: true})
}
},
复制代码

在父组件的methods中加入以下方法

/**
* 初始化所有的组件
*/
getUpdate(e) {
console.log('开始', e)
this.currentStatusArr.map((item, index) => { // 如果数组已经有当前组件id,则删除掉当前组件信息,重新初始化
if (item.menuId === e.menuId) {
this.currentStatusArr.splice(index, 1)
}
})
this.currentStatusArr.push(e)
},
/**
* 确认所有组件接口已经返回
*/
getBegin(e) {
console.log('结束')
this.currentStatusArr.map((item, index) => { // 如果数组已经有当前组件id,则删除掉当前组件信息,重新赋值
if (item.menuId === e.menuId) {
this.currentStatusArr.splice(index, 1)
}
})
this.currentStatusArr.push(e)
},
/**
* 判断页面加载
*/
judgePage() {
let flag = true
// 如果当前页面没有加载完,则返回false
this.currentStatusArr.map((item) => {
if (!item.flag) {
flag = false
}
})
// 返回false,说明某个页面接口数据没有加载完,提示用户等待
if (!flag) {
this.$message({
type:'warning',
message:'页面加载未完成,请稍后尝试'
})
return
}
}
复制代码

7.完整的js页面

7-1. 父组件页面js

// 导入组件
import overView from './report_overview/index'
import transparent from './report_transparent/index'
import reliable from './report_reliable/index'
// 定义组件
const components = {
overView,
transparent,
reliable,
}
// 关联组件,这里是把treeData里面定义的menuId和组件相关联
const componentsView = {
'1': 'overView',
'2': 'reliable',
'3': 'transparent',
}
export default {
data () {
return {
startTime: '',
treeData:   [
{
menuId: 1,
label: '一级 overView',
children: [],
},
{
menuId: 2,
label: '一级 reliable',
children: [],
},
{
menuId: 3,
label: '一级 transparent',
children: [],
},
]
defaultProps: {
children: 'children',
label: 'label'
},
compArr: [], // 渲染数组
currentStatusArr: [], // 确认数组内的组件是否渲染都完成
};
},
methods: {
/**
* 第一步,点击tree组件,可以知道选择的目录
* 第二步,把目录和组件相关联
* 第三步,根据这个目录,去寻找对应的组件渲染
*/
/**
* 选择节点,加载对应组件
* @param data
*/
handleCheck(e, a) {
console.log('一个', e, a);
// 选择节点
// 1. 添加或者删除节点对应的组件
// 2. a.checkedKeys是一个数组,对应当前选择的节点,所以点击的是时候根据a.checkedKeys,来添加对应的组件
this.compArr = []
// 处理未上线的路径
a.checkedKeys.map((item, index) => {
if (!componentsView[item]) {
this.$message({
message: '当前页面未添加报告,请联系管理员',
type: 'warning'
});
// 从数组取消当前复选框对应的id
a.checkedKeys.splice(index, 1)
}
})
// 按tress组件的选择增加对应的组件数据到数组
a.checkedKeys.map((item) => {
this.compArr.push({menuId: item, componentName: componentsView[item]})
})
// 按当前路径赋值到tree组件,当删除某一个复选框后,需要手动对当前tree节点赋值,不然不刷新
this.$refs.tree.setCheckedKeys(a.checkedKeys)
},
/**
* 返回需要渲染的组件
* @param item
* @returns {*}
*/
addComponents(item){
return components[item.componentName]
},
},
components: {}, // 没有用到普通组件的需要用的components
mounted () {
/*
* 实例挂载之后调用,但是并不是所有子组件也都一起挂载完成
*/
console.log ('5. mounted', this.$options.name);
// 添加默认组件
this.compArr = [{menuId: 1, componentName: 'overView'}]
}
}
复制代码

7-1. 子组件页面js

export default {
data () {
return {
loading: false
};
},
props:[],
watch: {},
computed: {},
methods: {
async getData() {
let api = '/'
let requestData = {}
this.loading = true
this.$emit('value-begin', {menuId: "00", flag: false})
let res = await this.$Http.axiosPost(api, requestData)
if (res.code === 200) {
this.loading = false
this.$emit('value-updated', {menuId: "00", flag: true})
}
},
},
mounted () {
/*
* 实例挂载之后调用,但是并不是所有子组件也都一起挂载完成
*/
console.log ('5. mounted');
this.toBase64()
},
};
复制代码

8. 待优化的点

组件的关联应该是动态的,后台返回关联数据,前端根据关联数据来渲染对应的数据存储到数组内,而不是前端根据id来手动关联。

也就是2,3,4这几个步骤的数据应该是后台给,不是前端写死的,前端获取数据之后进行处理就行了。

(ps:这应该是一个解耦的过程,算不算java里面的控制反转?)

「朝花夕拾」- 0605期,总第六期

上一篇

超声波触觉系统HaptiRead:让盲文能在空中得到精确投放

下一篇

你也可能喜欢

从零开始解说vue中动态组件的创建和使用

长按储存图像,分享给朋友