共计 3091 个字符,预计需要花费 8 分钟才能阅读完成。
推动我实现这个功能的业务背景
最近接到一个让我很头疼的需求:产品要求我们系统页面上所有的模块都支持顺序的变动。
比如有 模块 A、B、C、D,可以无序的展示在页面上,我刚听到这个需求的时候我是崩溃的,如果是在项目开发之前提出这个需求,那么我的前期页面的架构肯定不会直接写死的。现在,如果想满足这个需求,我只能翻掉之前的页面重新开发 …..
目前项目是有八个模块,我是每个模块封装一个单独的组件,然后再 index 页面统一引入。
- 救命稻草
浏览了一番 vue 的官网,还是有所收获的。发现了动态组件 & 异步组件这个东西!!!简直是救命啊!!!
动态组件:
异步组件:
- 思路分析
有了动态组件这个东西之后,我们就可以根据:is 绑定不同的值来渲染不同的组件。比如,拿到后台给我们返回的要渲染组件顺序的数组,我们通过循环数组,构建出一个最终我们想要的数据格式。关键点在于动态修改 () => import(”) 里面的值。每个组件要传给子组件的值和接收子组件 emit 的事件也可以动态的绑定上去。好了,废话不多说了,贴代码吧!
- 代码
首先是 HTML 层:
<template>
<div class="temp">
<!-- tempList 是经过处理后的数组 -->
<div v-for="com in tempList" :key="com.key">
<component v-bind="com.props" v-on="com.fn" :is="com.app" />
</div>
</div>
</template>
js 层:
<script>
import axios from 'axios';
import Volume from "com/Volume";
import ServiceStatus from "com/ServiceStatus";
import FixStatus from "com/FixStatus";
export default {
name: 'about',
props: {msg: String},
data() {
return {
isShow: false,
tempList: [],
tempData: [],
VolumeOptions: 'VolumeOptionsValueFromParent',
ServiceStatusOptions: 'ServiceStatusOptionsValueFromParent',
FixStatusOptions: 'FixStatusOptionsValueFromParent'
};
},
created() {this.createTempData()
},
methods: {
// 获取组件的顺序
getTempList() {
// 这里是我自己用 nodejs mock 的一个接口,返回的数据在下面贴出来
return axios.get('http://localhost:9999/search/detail').then(res => {return res.data.data})
},
async createTempData() {const result = await this.getTempList();
// 动态修改 options 绑定的变量
result.forEach((val) => {
let key = val.tempName;
switch (key) {
case 'Volume':
val.options = this.VolumeOptions
break;
case 'ServiceStatus':
val.options = this.ServiceStatusOptions
break;
case 'FixStatus':
val.options = this.FixStatusOptions
break;
}
})
this.tempData = result;
console.log(this.tempData);
this.init()},
init() {
// 构建渲染页面组件的数组
this.tempList = this.tempData.map((value, index) => {
return {app: () => import(`com/${value.tempName}`), // 异步组件
key: index,
props: {options: value.options, // 传给子组件的 options},
fn: {change: this.changeTest // 接收来自子组件的 $emit 事件}
};
});
},
changeTest(e) {console.log('监听子组件得到的值是:' + e)
}
}
};
子组件代码:
1.Volume 组件:
<template>
<div id="test">
Volume page
<div @click="$emit('change','Volume')">props 的值:{{options}}</div>
</div>
</template>
<script>
export default {
name: 'Volume',
props: {
options: {
type: String,
default: ''
}
}
}
</script>
2.FixStatus 组件:
<template>
<div id="FixStatus" class="comm">
组件名:FixStatus page
<div @click="$emit('change','FixStatus')">props 的值:{{options}}</div>
</div>
</template>
<script>
export default {
name: 'FixStatus',
props: {
options: {
type: String,
default: ''
}
}
}
</script>
<style lang="scss" scoped>
@import url('../assets/scss/comm.scss');
</style>
3.ServiceStatus 组件:
<template>
<div id="ServiceStatus" class="comm">
组件名:ServiceStatus page
<div @click="$emit('change','ServiceStatus')">props 的值:{{options}}</div>
</div>
</template>
<script>
export default {
name: 'ServiceStatus',
props: {
options: {
type: String,
default: ''
}
}
}
</script>
<style lang="scss" scoped>
@import url('../assets/scss/comm.scss');
</style>
接口返回的数据:
{"code":"0000","msg":"请求成功!","data":[{"id":0,"tempName":"ServiceStatus","options":"''"},{"id":1,"tempName":"Volume","options":"''"},{"id":2,"tempName":"FixStatus","options":"''"}]}
data 的数组就是我们可以自定义顺序的数组。好了,是不是可以随意的玩起来了!下面看一下 demo 页面效果吧。
- 五百万项目的效果
可以看到:页面组件的排列顺序就是根据接口返回的顺序排列的、每个子组件 props 得到的值也是可以的、控制台 console 是我点击不同组件,emit 给父组件的值。
这是我目前想到最妥当的方案,如果有巨佬有更好的思路,欢迎指导!扣扣 602353272。
溜了溜了 ….