<div> <Color></Color> <Button></Button> <Radio></Radio> <Checkbox></Checkbox> <Inputer></Inputer> <Autocomplete></Autocomplete> <InputNumber></InputNumber> //... </div>
同时需要监听一下editingActionType值的变化来滚动到对应组件的位置:
<script> { watch: { '$store.state.editingActionType'(newVal) { this.scrollTo(newVal) } }, methods:{ scrollTo(id) { switch (id) { case 'Input': id = 'Inputer' break; default: break; } let component = this.$children.find((item) =>{ return item.$options._componentTag === id }) if (component) { let el = component._vnode.elm let top = el.getBoundingClientRect().top + document.documentElement.scrollTop document.documentElement.scrollTop = top - 20 } } } } </script>
编辑区域
编辑区域主要分为三部分,工具栏、选择栏、控件区。这部分是本项目的核心也是最复杂的一部分。
先看一下变量列表的数据结构:
{ "name": "Color",// 组件类型/类别 "config": [{// 配置列表 "type": "color",// 变量类型,根据此字段渲染对应类型的控件 "key": "$--color-brand",// sass变量名 "value": "#e72528",// sass变量对应的值,可以是具体的值,也可以是sass变量名 "category": "Brand Color"// 列表,用来分组进行显示 }] }
此列表是后端返回的,选择器的选项是遍历该列表取出所有的name字段的值而组成的。
因为有些变量的值是依赖另一个变量的,所依赖的变量也有可能还依赖另一个变量,所以需要对数据进行处理,替换成变量最终的值,实现方式就是循环遍历数据,这就要求所有被依赖的变量也存在于这个列表中,否则就找不到了,只能显示变量名,所以这个实现方式其实是有待商榷的,因为有些被依赖的变量它可能并不需要或不能可编辑,本项目目前版本是存在此问题的。
此外还需要和当前编辑中的主题变量的值进行合并,处理如下:
// Editor组件 async getVariable() { try { // 获取变量列表,res.data就是变量列表,数据结构上面已经提到了 let res = await api.getVariable() // 和当前主题变量进行合并 let curTheme = store.getUserThemeByNameFromStore(this.$store.state.editingTheme) || {} let list = [] // 合并 list = this.merge(res.data, curTheme.theme) // 变量进行替换处理,因为目前存在该情况的只有颜色类型的变量,所以为了执行效率加上该过滤条件 list = store.replaceVariable(list, ['color']) // 排序 list = this.sortVariable(list) this.variableList = list // 存储到vuex this.$store.commit('updateVariableList', this.variableList) } catch (error) { console.log(error) } }
merge方法就是遍历合并对应变量key的值,主要看replaceVariable方法:
function replaceVariable(data, types) { // 遍历整体变量列表 for(let i = 0; i < data.length; i++) { let arr = data[i].config // 遍历某个类别下的变量列表 for(let j = 0; j < arr.length; j++) { // 如果不在替换类型范围内的和值不是变量的话就跳过 if (!types.includes(arr[j].type) || !checkVariable(arr[j].value)) { continue } // 替换处理 arr[j].value = findVariableReplaceValue(data, arr[j].value) || arr[j].value } } return data }
findVariableReplaceValue方法通过递归进行查找:
function findVariableReplaceValue(data, value) { for(let i = 0; i < data.length; i++) { let arr = data[i].config for(let j = 0; j < arr.length; j++) { if (arr[j].key === value) { // 如果不是变量的话就是最终的值,返回就好了 if (!checkVariable(arr[j].value)) { return arr[j].value } else {// 如果还是变量的话就递归查找 return findVariableReplaceValue(data, arr[j].value) } } } } }
接下来是具体的控件显示逻辑,根据当前编辑中的类型对应的配置数据进行渲染,模板如下:
// Editor组件 <template> <div> <div v-for="items in data" :key="items.name"> <div>{{items.name}}</div> <ul> <li v-for="item in items.list" :key="item.key"> <div>{{parseName(item.key)}}</div> <Control :data="item" @change="valueChange"></Control> </li> </ul> </div> </div> </template>
data是对应变量类型里的config数据,是个计算属性: