效果展示:
前言:隨著各公司定制化需求的不斷攀升,公司對(duì)低代碼、組態(tài)化的開發(fā)需求日漸迫切。也許是研發(fā)任務(wù)節(jié)點(diǎn)將至,也許是為順應(yīng)時(shí)代潮流,我也是去學(xué)習(xí)并實(shí)踐了一番。如圖所示調(diào)研后是正式上線的一期組態(tài)化版本,主要應(yīng)對(duì)不同甲方的多站概覽頁面的定制化需求,此處為了脫敏,已將相關(guān)logo去掉,只保留了功能頁面。
功能簡(jiǎn)介:
左側(cè)組件區(qū)域特意做了選中態(tài),小眼睛預(yù)覽浮框態(tài)等交互,右側(cè)內(nèi)容區(qū)域支持增加、刪除、退出、重置、預(yù)覽 、保存、應(yīng)用等操作,以及組態(tài)化最重要的功能點(diǎn)--隨意拖拽換位,后期考慮增加屬性面板支持對(duì)拖拽進(jìn)來的組件進(jìn)行寬高、顏色等的二次編輯修飾。
具體實(shí)現(xiàn):
1、實(shí)現(xiàn)流程依據(jù)
通過json實(shí)現(xiàn),預(yù)先定義好描述組件的json,json包含了當(dāng)前組件數(shù)據(jù)和當(dāng)前組件的樣式屬性數(shù)據(jù)等,并通過組件生成器將將描述組件的json結(jié)合起來渲染出實(shí)際組件,當(dāng)修改樣式屬性時(shí),組件樣式同步更新;
示例json:
json:{
fieldid:"",
name:"Input",
label:"單行文本",
icon:"input01",
placeholder:"請(qǐng)輸入",
value:"",
rules:{},
style:{},//組件的樣式
setting:{},//組件的其他屬性,比如:row:2
實(shí)現(xiàn)原理思維導(dǎo)圖:
2、實(shí)現(xiàn)詳情介紹
此需求基于開源的vue.draggable ^2.24.3,Vue項(xiàng)目首先需要去npm i -S vuedraggable下載vue.draggable相關(guān)依賴,并導(dǎo)入注冊(cè)draggable組件。如果是原生js直接CDN形式引用vuedraggable壓縮文件即可。建議沒看過我初階版本博客的小伙伴去看一下上篇文章再來,沿襲上篇代碼還是分組件區(qū)跟內(nèi)容區(qū)兩個(gè)group,group要名稱一致才可以建立拖拽關(guān)系,那么假設(shè)我們內(nèi)容區(qū)域group起名module,那么組件內(nèi)區(qū)域應(yīng)該也命module,結(jié)合展開面板組件使用那么json結(jié)構(gòu)如下:
componentsList:[
{
key: "1",
name: "頂部指標(biāo)欄",
group: { name: "module", pull: "clone", put: false },
child: [
{
id: 1,
type: 0,
col: 24,
name: "默認(rèn)樣式",
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: "默認(rèn)樣式",
imgSrc: "TopIndicator",
componentName: "TopIndicator",
activeKey: false
},
{
id: 4,
type: 0,
col: 24,
name: "默認(rèn)樣式",
imgSrc: "IncomeIndicators",
componentName: "IncomeIndicators",
activeKey: false
},
......
]
內(nèi)容區(qū)代碼,實(shí)現(xiàn)思路是用:is="item.componentName"去對(duì)應(yīng)組件名注冊(cè)寫好的組件,這樣就可以在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>
小眼睛顯示預(yù)覽圖浮框不建議用hover去做,因?yàn)檫@里樣式涉及overflow: hidden;如下圖用鼠標(biāo)事件去做會(huì)更好。
methods:
// 鼠標(biāo)移入顯示浮態(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;
// 判斷當(dāng)前鼠標(biāo)位置加上面板位置大于窗口寬度,表示超出不足以顯示,定位向上進(jìn)行定位
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;
},
// 鼠標(biāo)移出隱藏浮態(tài)框
panelHide() {
this.panelFlag = false;
this.panelName = "";
this.panelImgSrc = undefined;
},
最后再補(bǔ)上一個(gè)組件的刪除函數(shù),因?yàn)閮?nèi)容區(qū)刪除要聯(lián)動(dòng)把組件區(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)作不易,點(diǎn)贊支持!!!