效果展示:
前言:隨著各公司定制化需求的不斷攀升烤送,公司對低代碼、組態(tài)化的開發(fā)需求日漸迫切糠悯。也許是研發(fā)任務節(jié)點將至帮坚,也許是為順應時代潮流,我也是去學習并實踐了一番互艾。如圖所示調(diào)研后是正式上線的一期組態(tài)化版本试和,主要應對不同甲方的多站概覽頁面的定制化需求,此處為了脫敏纫普,已將相關(guān)logo去掉阅悍,只保留了功能頁面。
功能簡介:
左側(cè)組件區(qū)域特意做了選中態(tài)昨稼,小眼睛預覽浮框態(tài)等交互节视,右側(cè)內(nèi)容區(qū)域支持增加、刪除假栓、退出寻行、重置、預覽 匾荆、保存拌蜘、應用等操作,以及組態(tài)化最重要的功能點--隨意拖拽換位牙丽,后期考慮增加屬性面板支持對拖拽進來的組件進行寬高简卧、顏色等的二次編輯修飾。
具體實現(xiàn):
1烤芦、實現(xiàn)流程依據(jù)
通過json實現(xiàn)贞滨,預先定義好描述組件的json,json包含了當前組件數(shù)據(jù)和當前組件的樣式屬性數(shù)據(jù)等拍棕,并通過組件生成器將將描述組件的json結(jié)合起來渲染出實際組件晓铆,當修改樣式屬性時,組件樣式同步更新绰播;
示例json:
json:{
fieldid:"",
name:"Input",
label:"單行文本",
icon:"input01",
placeholder:"請輸入",
value:"",
rules:{},
style:{},//組件的樣式
setting:{},//組件的其他屬性骄噪,比如:row:2
實現(xiàn)原理思維導圖:
2、實現(xiàn)詳情介紹
此需求基于開源的vue.draggable ^2.24.3蠢箩,Vue項目首先需要去npm i -S vuedraggable下載vue.draggable相關(guān)依賴链蕊,并導入注冊draggable組件事甜。如果是原生js直接CDN形式引用vuedraggable壓縮文件即可。建議沒看過我初階版本博客的小伙伴去看一下上篇文章再來滔韵,沿襲上篇代碼還是分組件區(qū)跟內(nèi)容區(qū)兩個group逻谦,group要名稱一致才可以建立拖拽關(guān)系,那么假設我們內(nèi)容區(qū)域group起名module陪蜻,那么組件內(nèi)區(qū)域應該也命module邦马,結(jié)合展開面板組件使用那么json結(jié)構(gòu)如下:
componentsList:[
{
key: "1",
name: "頂部指標欄",
group: { name: "module", pull: "clone", put: false },
child: [
{
id: 1,
type: 0,
col: 24,
name: "默認樣式",
imgSrc: "TopIndicator",
componentName: "TopIndicator",
activeKey: true
},
{
id: 2,
type: 1,
col: 24,
name: "樣式一",
imgSrc: "TopIndicatorOne",
componentName: "TopIndicator",
activeKey: false
},
{
id: 3,
type: 2,
col: 24,
name: "樣式二",
imgSrc: "TopIndicatorTwo",
componentName: "TopIndicator",
activeKey: false
}
]
},
......
]
組件區(qū)域代碼
<div class="left-components beautify-scroll">
<a-collapse v-model="activeKey">
<a-collapse-panel
:key="item.key"
:header="item.name"
v-for="item in componentsList"
>
<draggable
v-model="item.child"
draggable=".li"
v-bind="dragOptions"
:options="{ sort: false, group: item.group }"
>
<div
v-for="d in item.child"
:key="d.id + 'item'"
:class="[
'li',
d.componentName,
d.col == 12 ? 'w5' : null,
d.activeKey ? 'active' : null
]"
>
<div class="txt">{{ d.name }}</div>
<img
class="img"
:src="
require(`@/assets/images/configuration/${d.imgSrc}.png`)
"
alt=""
/>
<div
class="eyes"
@mouseover="panelShow($event, d, item)"
@mouseout="panelHide"
></div>
</div>
<div
:class="[
'amplifier-img-box',
panelComponentName
]"
:style="{ top: panelTop, left: panelLeft }"
v-show="
panelFlag && panelParentKey == item.key
"
>
<div class="panel-title">
{{ panelName }}
</div>
<img
class="panel-img"
:src="panelImgSrc"
alt=""
/>
</div>
</draggable>
</a-collapse-panel>
</a-collapse>
</div>
內(nèi)容區(qū)json
contentList:[
{
id: 1,
type: 0,
col: 24,
name: "默認樣式",
imgSrc: "TopIndicator",
componentName: "TopIndicator",
activeKey: false
},
{
id: 4,
type: 0,
col: 24,
name: "默認樣式",
imgSrc: "IncomeIndicators",
componentName: "IncomeIndicators",
activeKey: false
},
......
]
內(nèi)容區(qū)代碼,實現(xiàn)思路是用:is="item.componentName"去對應組件名注冊寫好的組件宴卖,這樣就可以在draggable的渲染布局里面渲染具體組件
<draggable
class="content beautify-scroll"
group="module"
v-bind="dragOptions"
:list="contentList"
@change="toChange"
>
<div
v-for="(item, index) in contentList"
:key="'r' + index"
:class="[
'item',
item.componentName,
item.col == 12 ? 'w5' : null
]"
>
<component
:key="'c' + item.componentName + item.type"
:is="item.componentName"
:isEdit="true"
:type="Number(item.type)"
@click.native="selectContentItem(item)"
:class="[
item.id == contentActiveId ? 'active' : null
]"
></component>
<div
v-show="item.id == contentActiveId"
class="delbtn"
@click="del(item, index)"
></div>
</div>
</draggable>
小眼睛顯示預覽圖浮框不建議用hover去做滋将,因為這里樣式涉及overflow: hidden;如下圖用鼠標事件去做會更好。
methods:
// 鼠標移入顯示浮態(tài)框
panelShow(e, d, item) {
console.log(e, d, item);
this.panelName = item.name + " - " + d.name;
this.panelComponentName = d.componentName;
this.panelImgSrc = require(`@/assets/images/configuration/${d.imgSrc}.png`);
// 獲取窗口寬度
let windowHeight =
window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight;
// 判斷當前鼠標位置加上面板位置大于窗口寬度症昏,表示超出不足以顯示随闽,定位向上進行定位
if (e.clientY + 276 > windowHeight) {
this.panelTop = e.clientY - 296 + "px";
} else {
this.panelTop = e.clientY - 40 + "px";
}
this.panelLeft = e.clientX + 26 + "px";
this.panelParentKey = item.key;
this.panelFlag = true;
},
// 鼠標移出隱藏浮態(tài)框
panelHide() {
this.panelFlag = false;
this.panelName = "";
this.panelImgSrc = undefined;
},
最后再補上一個組件的刪除函數(shù),因為內(nèi)容區(qū)刪除要聯(lián)動把組件區(qū)選中態(tài)去除肝谭,所以這里的刪除里面要多一些邏輯控制
del(el, idx) {
this.contentList.splice(idx, 1);
// 刪除 取消框選態(tài)
this.componentsList.map((item) => {
item.child.map((i) => {
if (i.id == el.id) {
i.activeKey = false;
}
});
});
},
創(chuàng)作不易掘宪,點贊支持!H林颉添诉!