解決vue單頁(yè)面多個(gè)組件嵌套監(jiān)聽(tīng)瀏覽器窗口變化問(wèn)題
需求
最近公司有個(gè)大屏展示項(xiàng)目(如下圖)

頁(yè)面的元素需要做響應(yīng)式監(jiān)聽(tīng),圖表需要跟著窗口響應(yīng)變化
問(wèn)題
每一個(gè)圖表都被我寫(xiě)成了一個(gè)組件,然后就在每一個(gè)組件里寫(xiě)了一串代碼,監(jiān)聽(tīng)瀏覽器變化
結(jié)果只有父組件的代碼生效
mounted(){
window.onresize = () => { //當(dāng)窗口發(fā)生改變時(shí)觸發(fā)
//
};
}
原因
經(jīng)簡(jiǎn)單測(cè)試后發(fā)現(xiàn),同一個(gè)路由頁(yè)面只能注冊(cè)一次瀏覽器窗口監(jiān)聽(tīng)事件,第二次注冊(cè)的會(huì)覆蓋第一次注冊(cè)
下邊代碼即可測(cè)試
mounted(){
window.onresize = () => { //當(dāng)窗口發(fā)生改變時(shí)觸發(fā)
console.log(1)
};
window.onresize = () => { //當(dāng)窗口發(fā)生改變時(shí)觸發(fā) (會(huì)覆蓋上一個(gè)函數(shù))
console.log(2)
};
}
父子嵌套組件同理,子組件生命周期執(zhí)行在父組件之前,父組件函數(shù)會(huì)覆蓋子組件函數(shù)
解決方案
1、只在父頁(yè)面寫(xiě)個(gè)監(jiān)聽(tīng),但是通過(guò)組件傳值的方式傳給子組件,并且子組件用watch監(jiān)聽(tīng)傳值的變化,響應(yīng)改變
2、假如是多層組件嵌套,用vuex可能會(huì)更省力
補(bǔ)充知識(shí):vue/組件嵌套/無(wú)限嵌套/嵌套組件消息傳遞/嵌套父子組件傳值
目前接到一個(gè)需求,是我之前從來(lái)沒(méi)有實(shí)踐過(guò)的,正好趁此機(jī)會(huì)做一個(gè)深度剖析,并記錄下這次的成長(zhǎng),并分享給大家。
需求文檔
一 、(一個(gè)廠商編號(hào)和一個(gè)版本號(hào))唯一決定一個(gè)配置
二 、 配置內(nèi)容支持無(wú)限嵌套
三、配置數(shù)據(jù)格式示例(配置包括項(xiàng)和模塊):
{
"vendorId": "IL03#sub_01",
"version": "9.0.0",
"config": {
"module-1": {
"property-1": "value-1",
"property-2": "value-2",
"property-3": "value-3",
"module-1_1": {
"property-1_1": "value-1_1",
"property-1_2": "value-1_2",
"property-1_3": "value-1_3"
}
},
"module-2": {
"property-4": "value-4",
"property-5": "value-5"
}
}
}
四、配置成果物如下:

需求分解
一個(gè)簡(jiǎn)單的嵌套組件:
<template>
<div>
<span>{{data.content}}<span>
<div>
<nested :data="data.child"></nested>
<div>
</div>
</template>
<script>
export default {
name: 'nested',
props: ['data']
}
</script>
我們給最外層的組件(根嵌套組件)綁定形如
{
"content": "value",
"child": {
"content": "value-1"
"child": {
"content": "value-1_1"
......
}
}
}
的數(shù)據(jù)結(jié)構(gòu),就可以看見(jiàn)效果了,是不是和我們前面需求的數(shù)據(jù)結(jié)構(gòu)很像?
開(kāi)始動(dòng)工
step1:最外層列表展示
這里作為靜態(tài)路由頁(yè)面展示即可(分頁(yè)、查詢、刪除功能在這里做)
<!-- 這里使用了EL-UI -->
<template>
<!-- 應(yīng)用配置入口 -->
<div class="app-config-wrap">
<!-- 增 -->
<div class="app-config-add">
<el-button type="primary" size="mini" @click="handleClickAdd">新增配置</el-button>
</div>
<!-- 查 -->
<div class="app-config-search">
<div class="label" @click="isShowFilter = !isShowFilter">
<span class="text">查詢App配置</span>
<span class="el-icon-caret-right" v-if="!isShowFilter"></span>
<span class="el-icon-caret-bottom" v-else></span>
</div>
<div class="clear-all" @click="handleClearAll" v-if="isShowFilter" title="點(diǎn)擊清空所有查詢條件">
<span class="text">清空條件</span>
</div>
<div class="form-wrap" v-show="isShowFilter">
<div class="by-vendorId">
<el-input type="text" size="mini" placeholder="按廠商編號(hào)查詢" clearable v-model.trim="vendorId">
</el-input>
</div>
<div class="by-version">
<el-input type="text" size="mini" placeholder="按版本號(hào)查詢" clearable v-model.trim="version">
</el-input>
</div>
<div class="search-button">
<el-button type="primary" size="mini" @click="handleClickSearch">查 詢</el-button>
</div>
</div>
</div>
<div class="app-config-main" :style="tableHeight">
<el-table size="mini" height="100%" :data="configList" stripe @row-click="handleClickRow"
highlight-current-row style="width: 100%;">
<el-table-column type="index" label="No." width="60"></el-table-column>
<el-table-column prop="vendorId" label="廠商編號(hào)" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="version" label="版本號(hào)" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="operation" label="操作">
<template slot-scope="scope">
<!-- 刪 -->
<el-button type="danger" size="mini" @click="handleClickDelete(scope.row.id)">刪除配置</el-button>
</template>
</el-table-column>
</el-table>
</div>
<el-pagination class="pagination" v-if="total" background small :current-page="pageNum"
:page-sizes="[10, 20, 40, 60]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper"
:total="parseInt(total)" @current-change="changePageNo" @size-change="changePageSize">
</el-pagination>
</div>
</template>
<script>
export default {
name: 'appConfig',
components: {},
props: [],
data () {
return {
isShowFilter: false,
vendorId: '',
version: '',
pageNum: 1,
pageSize: 20,
total: 0,
configList: [{ // 假數(shù)據(jù)
id: 1,
vendorId: 'cjm',
version: '10.0.0'
}]
}
},
computed: {
tableHeight () {
return this.isShowFilter ? { height: 'calc(100% - 129px)' } : { height: 'calc(100% - 90px)' }
}
},
methods: {
handleClearAll () {
this.vendorId = ''
this.version = ''
},
handleClickSearch () { // 這里發(fā)送查詢請(qǐng)求
},
changePageNo (val) { // 這里發(fā)送分頁(yè)請(qǐng)求
this.pageNum = val
},
changePageSize (val) { // 這里發(fā)送分頁(yè)請(qǐng)求
this.pageSize = val
},
handleClickDelete (id) { // 這里發(fā)送刪除請(qǐng)求
},
handleClickAdd () { // 使用路由方式跳轉(zhuǎn)到配置頁(yè)面(增加配置和修改配置同一頁(yè)面即可)
this.$router.push({
name: 'configData',
query: {}
})
},
handleClickRow (row) { // 通過(guò)id讓配置頁(yè)面初始化時(shí)請(qǐng)求數(shù)據(jù),在跳轉(zhuǎn)頁(yè)面中watch即可
this.$router.push({
name: 'configData',
query: {
id: row.id
}
})
}
}
}
</script>
// 樣式我就不貼了,節(jié)省篇幅
step2:動(dòng)態(tài)路由頁(yè)準(zhǔn)備
由于配置頁(yè)面展示是根據(jù)廠商編號(hào)和版本號(hào)動(dòng)態(tài)改變的,所以這里用到
this.$router.push({
name: 'configData',
query: {
id: row.id
}
})
來(lái)實(shí)現(xiàn)動(dòng)態(tài)路由頁(yè)面,這里也需要引入我們的根嵌套組件(嵌套入口)。
<template>
<div class="config-data-warp">
<div class="config-head">
<span class="text">廠商編號(hào):</span>
<el-input class="config-input" type="text" size="mini" placeholder="廠商編號(hào)"
clearable v-model.trim="vendorId">
</el-input>
</div>
<div class="config-head">
<span class="text">版本號(hào):</span>
<el-input class="config-input" type="text" size="mini" placeholder="版本號(hào)"
clearable v-model.trim="version">
</el-input>
</div>
<div class="config-main">
<config-module :data="config" :root="true"
:commit="commit" @commit="handlerCommit"></config-module>
</div>
<el-button class="config-commit-btn" type="primary"
size="mini" @click="commit = true">確認(rèn)提交</el-button>
</div>
</template>
<script>
import configModule from './configModule'
export default {
name: 'configData',
components: {configModule},
data () {
return {
id: this.$route.id,
commit: false,
vendorId: '',
version: '',
config: {} // 這里放點(diǎn)假數(shù)據(jù)
}
},
mounted () { // 如果id存在,就去請(qǐng)求數(shù)據(jù)
if (id) { ... }
},
methods: {
handlerCommit (data) { // 這里是匯總數(shù)據(jù)的地方,記下來(lái),等下提到了好找
console.log(data)
this.commit = false
}
}
}
</script>
值得注意的是,確認(rèn)提交按鈕只是將commit變量置為true,而commit綁定在我們的嵌套組件中。
<div class="config-children" v-for="(value, index) in configJsonChildren" :key="index + 'child' + moduleName">
<config-module :index="index" @change="changeChildName" @commit="handlerCommit"
:commit="commit" :data="{key: value[0], child: value[1]}"></config-module>
</div>
這是嵌套組件的部分代碼,我們可以看到commit被原封不動(dòng)的傳遞給了子嵌套組件,也就是說(shuō),這里的commit變量起到通知所有嵌套組件執(zhí)行了提交動(dòng)作,這也是父組件控制子組件組件的唯一方式——傳遞數(shù)據(jù)變化props(或者使用vuex也可以)。
這里還有一點(diǎn),就是定義什么是嵌套部分,什么是嵌套外部分,顯然,廠商編號(hào)和版本號(hào)不屬于嵌套部分。
還有傳入的root變量,是為了控制根嵌套組件的名稱不可修改,所以傳個(gè)true就可以了。
step3:嵌套組件的實(shí)現(xiàn)(重點(diǎn))
這里梳理一下嵌套組件需要提供的功能點(diǎn):
1、能夠做到傳入數(shù)據(jù)的展示
2、能夠動(dòng)態(tài)添加項(xiàng)和模塊
3,能夠?qū)⑿薷牧说臄?shù)據(jù)傳遞出去
傳入數(shù)據(jù)的展示
我們?cè)倩剡^(guò)頭看看后臺(tái)傳給我們的數(shù)據(jù)格式:
{
"vendorId": "IL03#sub_01",
"version": "9.0.0",
"config": {
"module-1": {
"property-1": "value-1",
"property-2": "value-2",
"property-3": "value-3",
"module-1_1": {
"property-1_1": "value-1_1",
"property-1_2": "value-1_2",
"property-1_3": "value-1_3"
}
},
"module-2": {
"property-4": "value-4",
"property-5": "value-5"
}
}
}
從中我們是否可以提煉出每個(gè)嵌套組件的數(shù)據(jù)格式?
module: {
property-1: value-1,
property-2: value-2,
......
module-1: { ...... },
mpdule-2: { ...... },
......
}
而且,我們需要這個(gè)對(duì)象的key和value是可以被雙向綁定的。
可是我們想一下,對(duì)象的key可以雙向綁定嗎?顯然不能!
這也就是說(shuō),原始傳入的數(shù)據(jù)結(jié)構(gòu)并不能用,需要進(jìn)行處理:
<template>
<div class="config-module-warp">
<div class="config-head">
<!-- 根組件固定模塊名,或者說(shuō)不需要模塊名 -->
<span class="config-header-item" v-if="root">配置:</span>
<div class="config-header-item" v-else>
<el-input class="config-module-name" type="text" size="mini"
placeholder="模塊名" clearable v-model="moduleName" @change="changeModuleName"></el-input>
</div>
<el-button class="config-header-item" type="primary" size="mini"
@click="handleClickAddProperty">新增項(xiàng)</el-button>
<el-button class="config-header-item" type="primary" size="mini"
@click="handleClickAddModule">新增模塊</el-button>
<el-button v-if="root" class="config-btn" type="danger" size="mini"
@click="handleClickClear">清空配置</el-button>
<el-button v-else class="config-btn" type="danger" size="mini"
@click="handleClickDeleteModule">刪除模塊</el-button>
<div class="config-property" v-for="(value, index) in configJsonProperty"
:key="index + 'property'">
<el-input class="config-property-value" type="text" size="mini"
placeholder="key" clearable v-model="value[0]"></el-input> :
<el-input class="config-property-value" type="text" size="mini"
placeholder="value" clearable v-model="value[1]"></el-input>
<el-button class="config-header-item" type="danger" size="mini"
@click="handleClickDeleteProperty(index)">刪除該項(xiàng)</el-button>
</div>
<div class="config-children" v-for="(value, index) in configJsonChildren"
:key="index + 'child'">
<config-module :index="index" @change="changeChildName" @commit="handlerCommit"
:commit="commit" :data="{key: value[0], child: value[1]}"></config-module>
</div>
</div>
</template>
...
data () {
return {
moduleName: '', // 綁定當(dāng)前子模塊名
configJsonProperty: [], // 這里是子模塊的property
configJsonChildren: [], // 這里是子模塊下的子模塊(孖模塊^-^)
...
}
}
...
mounted () {
if (this.data && this.root) {
// 由于根節(jié)點(diǎn)是沒(méi)有模塊名的,數(shù)據(jù)的解析結(jié)構(gòu)是{key: moduleName, child: moduleValue},參上。
this.classify({child: this.data})
} else if (this.data) {
this.classify(this.data)
}
}
// 或者將引用根組件的地方改成下面這樣也可以:
// <config-module :data="{child: config}" :root="true" :commit="commit"
// @commit="handlerCommit"></config-module>
// _____________________________________
// mounted () {
// if (this.data) {
// this.classify(this.data)
// }
// }
...
classify (prop) {
let data = prop.child
this.moduleName = prop.key
for (let key in data) {
if (typeof data[key] === 'object') {
this.configJsonChildren.push([ // 這里將數(shù)組轉(zhuǎn)化為可以雙向綁定的二維數(shù)組
key,
data[key]
])
} else {
this.configJsonProperty.push([
key,
data[key]
])
}
}
}
實(shí)現(xiàn)動(dòng)態(tài)增加
只需要添加空項(xiàng)就行了,但由于模塊是由父組件傳入的,所以改變模塊名也需要同步改變父組件的模塊名,而這里就用到了props中的index,代表父組件中的位置。
handleClickAddProperty () {
this.configJsonProperty.push([
'',
''
])
},
handleClickAddModule () {
this.configJsonChildren.push([
'',
{}
])
},
changeModuleName (value) {
this.$emit('change', this.index, value)
},
changeChildName (index, name) {
this.$set(this.configJsonChildren[index], 0, name)
},
孿生兄弟:動(dòng)態(tài)刪除
其實(shí),增加數(shù)據(jù)和刪除數(shù)據(jù)無(wú)外乎就是,本地?cái)?shù)據(jù)本地改,外部數(shù)據(jù)同步改:
handleClickClear () {
// 如果本身就是空,就無(wú)需操作,防止誤操作,畢竟我挺討厭彈窗的
if (!this.configJsonProperty.length && !this.configJsonChildren.length) {
return
}
// 敏感操作給個(gè)彈窗
this.$confirm('確定清空所有配置?', '警告', {
confirmButtonText: '確定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 這個(gè)是本地觸發(fā)的哦!
this.configJsonProperty = []
this.configJsonChildren = []
})
},
handleClickDeleteProperty (index) { // 本地?cái)?shù)據(jù)本地改
this.configJsonProperty.splice(index, 1)
},
handleClickDeleteModule () {
// 外部數(shù)據(jù)傳出改,由于是刪除操作,外部銷(xiāo)毀了會(huì)直接導(dǎo)致本地銷(xiāo)毀,本地?zé)o需再銷(xiāo)毀
// 和改模塊名不一樣
// 改模塊名時(shí),雖然外部數(shù)據(jù)改變觸發(fā)了本地更新,但由于是push操作,并不會(huì)改變本地?cái)?shù)據(jù)
this.$emit('delete', this.index)
},
deleteModule (index) {
// 與handleClickDeleteProperty方法比較,一定要分清哪個(gè)是子組件觸發(fā),哪個(gè)是父組件觸發(fā)
this.configJsonChildren.splice(index, 1)
},
重中之重:提取這個(gè)樹(shù)結(jié)構(gòu)中的數(shù)據(jù)
數(shù)據(jù)在各個(gè)子組件中保存,怎么把它們提取出來(lái)呢?
聰明的你肯定馬上想到了我之前所說(shuō)的commit變量吧,它將這個(gè)動(dòng)作分發(fā)到了各個(gè)子組件。
所以,只要每個(gè)子組件聽(tīng)從命令,把數(shù)據(jù)層層上報(bào),是不是就完成了呢?
這就好比是公司總經(jīng)理想要開(kāi)發(fā)一個(gè)軟件,他就只要告訴各個(gè)部門(mén):
哎,你們軟件部負(fù)責(zé)做出軟件可行性方案;
你們市場(chǎng)部負(fù)責(zé)調(diào)查同類軟件和市場(chǎng)份額;
你們營(yíng)銷(xiāo)部趕快出爐軟件推廣方案,等等。
然后部門(mén)總監(jiān)給各項(xiàng)目經(jīng)理發(fā)小人物,然后項(xiàng)目經(jīng)理再分解任務(wù)成需求給你。
最后做完了,流程就是:你 -》經(jīng)理-》總監(jiān)-》總經(jīng)理。
在我們這份代碼中,也是這樣子的:
第一步:你要知道任務(wù)來(lái)了:
watch: {
commit (val) {
if (val) {
this.handleClickCommit() // 接到任務(wù)
} else {
this.commitData = {} // 這里也標(biāo)記一下
}
}
},
第一步:找到最底層的“你”,也就是找到這個(gè)樹(shù)組件的末梢節(jié)點(diǎn),
它的標(biāo)志是:
if (!this.configJsonChildren.length) { ...... } // 他沒(méi)有子節(jié)點(diǎn)了
d收集它的“工作成果”:
let obj = {}
this.configJsonProperty.forEach(v => {
if (v[0] && v[1]) {
obj[v[0]] = v[1]
} else {
this.$emit('error') // 如果有項(xiàng)不完整,可以報(bào)錯(cuò)
}
})
你覺(jué)得上面代碼有沒(méi)有小問(wèn)題?給你五秒想一想。
1
2
3
4
5
有沒(méi)有這樣一種情況?我們一不注意寫(xiě)了兩個(gè)同樣鍵名的項(xiàng),不管是寫(xiě)到了錯(cuò)的模塊里面還是怎樣。
那么在上面的代碼中,就會(huì)使得新值覆蓋舊值,就有可能導(dǎo)致嚴(yán)重的事故?。?!
所以我們改成:
handleClickCommit () {
if (!this.configJsonChildren.length) {
if (!this.moduleName && !this.root) {
this.$emit('error')
return
}
let obj = {}
for (let v of this.configJsonProperty) {
if (v[0] && v[1]) {
if (obj.hasOwnProperty(v[0])) {
this.$emit('error') // 啊,一不小心走神了
return
}
obj[v[0]] = v[1]
} else {
this.$emit('error')
// 這里不需要return是因?yàn)椴粫?huì)造成嚴(yán)重后果,當(dāng)然也可以加上
// 主要是我用這個(gè)功能時(shí)會(huì)一口氣添加好多項(xiàng),也不一定全填滿,省得一個(gè)個(gè)刪。
}
}
this.$emit('commit', { // 把數(shù)據(jù)給經(jīng)理?。?!這個(gè)殺千刀的,天天催!
key: this.moduleName, // 身份狗牌
value: obj
})
}
}
啊,工作終于提交了,再也不擔(dān)心了,接下來(lái)的事就交給經(jīng)理去做吧!
經(jīng)理:我手下管著這么多人,不可能來(lái)一個(gè)我上交一個(gè)吧?那就等他們?nèi)可辖涣耍以僬麄€(gè)打包上交吧。
首先第一步,我需要一個(gè)箱子來(lái)存他們的成果:
data () {
return {
moduleName: '',
configJsonProperty: [],
configJsonChildren: [],
commitData: {} // 存放成果的箱子
}
}
接下來(lái)就等他們上交了:
handlerCommit (data) {
if (!this.moduleName && !this.root) { // 領(lǐng)導(dǎo)也要有名字,但總經(jīng)理只有一個(gè)
this.$emit('error')
return
}
this.commitData[data.key] = data.value // 先按人頭收下成果
for (let item of this.configJsonChildren) {
if (!this.commitData.hasOwnProperty(item[0])) return // 如果沒(méi)收齊,繼續(xù)等待
}
// 歐耶,收齊了
let obj = {}
for (let v of this.configJsonProperty) { // 這個(gè)for循環(huán)可以封成一個(gè)函數(shù)的,畢竟寫(xiě)了兩次
if (v[0] && v[1]) {
if (obj.hasOwnProperty(v[0])) {
this.$emit('error')
return
}
obj[v[0]] = v[1]
} else {
this.$emit('error')
}
}
this.$emit('commit', {
key: this.moduleName,
value: Object.assign(obj, this.commitData) // 領(lǐng)導(dǎo)自己的成果加上員工的成果
})
}
還記得上面我讓你記下的地方嗎?
handlerCommit (data) {
console.log(data) // 匯總數(shù)據(jù),在這里可以發(fā)送給后臺(tái)了
this.commit = false // 任務(wù)完成標(biāo)志
}
watch: {
commit (val) {
if (val) {
this.handleClickCommit()
} else {
this.commitData = {} // 初始化子組件
}
}
},
到這里,嵌套組件也大致完工了,貼全代碼:
<template>
<div class="config-module-warp">
<div class="config-head">
<span class="config-btn" v-if="root">配置:</span>
<div class="config-btn" v-else>
<el-input class="config-module-name" type="text" size="mini" placeholder="模塊名"
clearable v-model="moduleName" @change="changeModuleName"></el-input>
</div>
<el-button class="config-btn" type="primary" size="mini"
@click="handleClickAddProperty">新增項(xiàng)</el-button>
<el-button class="config-btn" type="primary" size="mini"
@click="handleClickAddModule">新增模塊</el-button>
<el-button v-if="root" class="config-btn" type="danger" size="mini"
@click="handleClickClear">清空配置</el-button>
<el-button v-else class="config-btn" type="danger" size="mini"
@click="handleClickDeleteModule">刪除模塊</el-button>
</div>
<div class="config-property" v-for="(value, index) in configJsonProperty" :key="index + 'property'">
<el-input class="config-property-value" type="text" size="mini"
placeholder="key" clearable v-model="value[0]"></el-input> :
<el-input class="config-property-value" type="text" size="mini"
placeholder="value" clearable v-model="value[1]"></el-input>
<el-button class="config-btn" type="danger" size="mini"
@click="handleClickDeleteProperty(index)">刪除該項(xiàng)</el-button>
</div>
<div class="config-children" v-for="(value, index) in configJsonChildren" :key="index + 'child'">
<config-module :index="index" @change="changeChildName" @delete="deleteModule"
@commit="handlerCommit" :commit="commit" :data="{key: value[0], child: value[1]}"></config-module>
</div>
</div>
</template>
<script>
export default {
name: 'configModule',
props: ['data', 'root', 'commit', 'index'],
data () {
return {
moduleName: '',
configJsonProperty: [],
configJsonChildren: [],
commitData: {},
error: false
}
},
watch: {
commit (val) {
if (val) {
this.handleClickCommit()
} else {
this.commitData = {}
this.error = false
}
}
},
computed: {
},
mounted () {
if (this.data) {
this.classify(this.data)
}
},
methods: {
classify (prop) {
let data = prop.child
this.moduleName = prop.key
for (let key in data) {
if (typeof data[key] === 'object') {
this.configJsonChildren.push([
key,
data[key]
])
} else {
this.configJsonProperty.push([
key,
data[key]
])
}
}
},
handleClickAddProperty () {
this.configJsonProperty.push([
'',
''
])
},
handleClickAddModule () {
this.configJsonChildren.push([
'',
{}
])
},
handleClickClear () {
if (!this.configJsonProperty.length && !this.configJsonChildren.length) {
return
}
this.$confirm('確定清空所有配置?', '警告', {
confirmButtonText: '確定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.configJsonProperty = []
this.configJsonChildren = []
})
},
handleClickDeleteProperty (index) {
this.configJsonProperty.splice(index, 1)
},
handleClickDeleteModule () {
this.$emit('delete', this.index)
},
deleteModule (index) {
this.configJsonChildren.splice(index, 1)
},
changeModuleName (value) {
this.$emit('change', this.index, value)
},
changeChildName (index, name) {
this.$set(this.configJsonChildren[index], 0, name)
},
handleClickCommit () {
if (!this.configJsonChildren.length) {
if (!this.moduleName && !this.root) {
this.$emit('error')
return
}
let obj = {}
for (let v of this.configJsonProperty) {
if (v[0] && v[1]) {
if (obj.hasOwnProperty(v[0])) {
this.$emit('error')
return
}
obj[v[0]] = v[1]
} else {
this.$emit('error')
}
}
this.$emit('commit', {
key: this.moduleName,
value: obj
})
}
},
handlerCommit (data) {
if (!this.moduleName && !this.root) {
this.$emit('error')
return
}
this.commitData[data.key] = data.value
for (let item of this.configJsonChildren) {
if (!this.commitData.hasOwnProperty(item[0])) return
}
let obj = {}
for (let v of this.configJsonProperty) {
if (v[0] && v[1]) {
if (obj.hasOwnProperty(v[0])) {
this.$emit('error')
return
}
obj[v[0]] = v[1]
} else {
this.$emit('error')
}
}
this.$emit('commit', {
key: this.moduleName,
value: Object.assign(obj, this.commitData)
})
}
}
}
</script>
總結(jié)
其實(shí)聰明的人根本就不需要我總結(jié)嘛,代碼是最好的語(yǔ)言
所以這里我提出一些我的不足和沒(méi)做完的部分,不過(guò)都是細(xì)枝末節(jié)啦:
第一個(gè)是錯(cuò)誤的處理,我這邊沒(méi)有加上
第二個(gè)是模塊應(yīng)該有折疊功能,不然配置多看著就眼花繚亂,
不過(guò)v-show的使用大家應(yīng)該也是登峰造極了。
然后,大家有什么意見(jiàn)和建議都可以在下方反饋。
感謝大家看完這一篇長(zhǎng)文,么么噠~希望能給大家一個(gè)參考,也希望大家多多支持腳本之家
相關(guān)文章
Avue和Element-UI動(dòng)態(tài)三級(jí)表頭的實(shí)現(xiàn)
本文主要介紹了Avue和Element-UI動(dòng)態(tài)三級(jí)表頭的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
在vue中給列表中的奇數(shù)行添加class的實(shí)現(xiàn)方法
今天小編就為大家分享一篇在vue中給列表中的奇數(shù)行添加class的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
vue2.x中h函數(shù)(createElement)與vue3中的h函數(shù)詳解
h函數(shù)本質(zhì)就是createElement(),h函數(shù)其實(shí)是createVNode的語(yǔ)法糖,返回的就是一個(gè)Js普通對(duì)象,下面這篇文章主要給大家介紹了關(guān)于vue2.x中h函數(shù)(createElement)與vue3中h函數(shù)的相關(guān)資料,需要的朋友可以參考下2022-12-12
vue實(shí)現(xiàn)簡(jiǎn)易選項(xiàng)卡功能
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)簡(jiǎn)易選項(xiàng)卡功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06
通過(guò)一個(gè)簡(jiǎn)單的例子學(xué)會(huì)vuex與模塊化
這篇文章主要給大家介紹了關(guān)于如何通過(guò)一個(gè)簡(jiǎn)單的例子學(xué)會(huì)vuex與模塊化的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-11-11
Vue仿微信app頁(yè)面跳轉(zhuǎn)動(dòng)畫(huà)效果
這篇文章主要介紹了Vue仿微信app頁(yè)面跳轉(zhuǎn)動(dòng)畫(huà)效果,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08
詳解vuex結(jié)合localstorage動(dòng)態(tài)監(jiān)聽(tīng)storage的變化
這篇文章主要介紹了詳解vuex結(jié)合localstorage動(dòng)態(tài)監(jiān)聽(tīng)storage的變化,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05

