JsonTransfer
以昆侖三級聯動類目為例 對于后端返回的數據 我們可能需要對這些字段進行特殊的配置(如改名)等才能拿到我們可以直接使用的數據。除此之外,消息訂閱比較混亂。
我們期望的消息訂閱模式如下:
// 監聽 listen 事件
this.jsonTransfer.on("listen", value => {
// 處理 value 值 value 為后端字符串經過特殊處理之后返回給我們需要的字符串
this.resOptions = value;
});
// 獲取后端數據 并觸發監聽事件
axios.get(`${dataObj[value]}`).then(res => {
// 拿到后端數據之后 觸發 listen 事件
this.jsonTransfer.emit("listen", {
returnKeys: ["cat_id", "cat_name", "depth", "rank"],
keymap: {
label: "cat_name",
value: "cat_name",
depth: "depth"
},
data: res.data.data[0]
});
});
我們將枯燥而繁瑣的數據格式轉換 類名轉換 提供了一個公共的方法取處理
react 和 vue 中使用的時候 掛載在全局對象上即可
class JsonForest {
constructor () {
this.eventList = []
this.data = ''
this.keymap = {
name: 'cat_name',
id: 'cat_id',
depth: 'depth'
}
this.returnKeys = ['cat_id', 'cat_name', 'depth', 'rank']
this.JsonTransfer = new JsonTransfer()
}
init (option) {
this.option = this.checkParam(option) ? option : ''
this.data = this.checkParam(option.data)
? JSON.parse(JSON.stringify(option.data))
: ''
this.keymap = this.checkParam(option.keymap) ? option.keymap : ''
this.returnKeys = this.checkParam(option.returnKeys)
? option.returnKeys
: ''
}
checkParam (param) {
// 如果為空字符串、 空對象、空數組 以及 undefined null 等值的時候 返回 false 否則返回 true
if (Object.prototype.toString.call(param) === '[object Array]') {
return !!param.length
} else if (Object.prototype.toString.call(param) === '[object Object]') {
return !!Object.keys(param).length
} else {
return !!param
}
}
validateLegal (returnKeys, keymap) {
if (Object.prototype.toString.call(returnKeys) !== '[object Array]') {
throw new Error('returnKeys字段,必須為數組')
} else if (Object.prototype.toString.call(keymap) !== '[object Object]') {
throw new Error('keymap字段,必須為對象')
} else {
return true
}
}
emit (type, option) {
let arr = this.eventList[type]
if (!arr) {
/**
* 沒有 on 的時候 emit的兼容
*/
arr = []
}
// 校驗 data 存在的情況下 returnKeys為數組 keymap為對象的合法性
this.validateLegal(this.returnKeys, this.keymap)
/**
* 掛載參數 進行整體校驗 不符合規范的 轉化為空字符串
*/
this.init(option)
// option 不傳 或者 data 不傳 則可認為在執行訂閱和發布任務 不做 dom 轉化
if (!this.option || !this.data) {
arr.forEach((item, index) => {
item()
})
} else {
/**
* 1. 檢驗 returnKeys 如果不對 給出報錯
* 2. 檢驗 keymaps 如果映射的類名不對 給出報錯
*
*/
if (this.returnKeys) {
this.data = this.JsonTransfer.getDataFormReturnKeys(this.data, this.returnKeys)
}
if (this.keymap) {
this.data = this.JsonTransfer.replaceKeymap(this.data, this.keymap, this.returnKeys)
}
arr.forEach(item => {
item(this.data, this.option)
})
}
}
on (type, callback) {
if (!this.eventList[type]) {
this.eventList[type] = []
}
this.eventList[type].push(callback)
}
}
class JsonTransfer {
getDataFormReturnKeys (data, returnKeys) {
let result = {}
if (Object.prototype.toString.call(data) === '[object Array]') {
result = data.map(item => {
return this.getDataFormReturnKeys(item, returnKeys)
})
} else if (Object.prototype.toString.call(data) === '[object Object]') {
let prevKeys = Object.keys(data)
returnKeys.forEach(item => {
// 原先數據中存在的key 值 才會生效
if (prevKeys.includes(item)) {
result = Object.assign(result, {
[item]: this.getDataFormReturnKeys(data[item], returnKeys)
})
}
})
} else {
return data
}
return result
}
checkKeymapRepeat (keymap) {
let arr = Object.values(keymap)
let hash = {}
for (let i = 0; i < arr.length; i++) {
if (hash[arr[i]]) {
return true
}
hash[arr[i]] = true
}
return false
}
replaceRepeatKeymap (data, keymap, returnKeys) {
let result = {}
if (Object.prototype.toString.call(data) === '[object Array]') {
result = data.map(item => {
return this.replaceRepeatKeymap(item, keymap, returnKeys)
})
} else if (Object.prototype.toString.call(data) === '[object Object]') {
for (let key in keymap) {
let dataKey = keymap[key]
if (data.hasOwnProperty(dataKey)) {
result = Object.assign(result, {
[key]: this.replaceRepeatKeymap(data[dataKey], keymap, returnKeys)
})
}
}
// 補充returnKeys 遺留的 key 值
let filterArr = returnKeys.filter((item) => {
return !Object.values(keymap).includes(item)
})
if (filterArr.length) {
filterArr.forEach((key) => {
if (data.hasOwnProperty(key)) {
result = Object.assign(result, {
[key]: this.replaceRepeatKeymap(data[key], keymap, returnKeys)
})
}
})
}
} else {
return data
}
return result
}
replaceKeymap (data, keymap, returnKeys) {
let str = JSON.stringify(data)
/**
* 1. keymap 中存在相同的 value 值 (特殊情況)
* keymap: {
label: "cat_name",
value: "cat_name",
depth: "depth"
},
* 2. keymap 中的 value 值都不相同(正常情況)
*/
if (this.checkKeymapRepeat(keymap)) {
return this.replaceRepeatKeymap(data, keymap, returnKeys)
} else {
for (let key in keymap) {
let chiledStr = keymap[key]
str = str.replace(new RegExp(chiledStr, 'g'), key)
}
return JSON.parse(str)
}
}
}
export default JsonForest
使用說明
api | 使用方法 | 說明 |
---|---|---|
data | 賦值數據 | 數據源 如果不傳 將不對數據做任何處理 |
returnKeys | ['cat_id', 'cat_name', 'depth', 'rank'] | 需要返回的字段,以數組的形式包圍 |
keymap | {label: 'cat_name', value: 'cat_name',} |
映射改變的字段 ,以對象的形式包裹,支持1對1、1對多 |
使用
mounted () {
this.jsonTransfer.on('listen', value => {
console.log('111')
console.log(value)
this.resOptions = value
})
},
methods: {
chooseValue (value) {
console.log(value)
axios.get(`${dataObj[value]}`).then(res => {
console.log(this.jsonTransfer)
this.jsonTransfer.emit('listen', {
returnKeys: ['cat_id', 'cat_name', 'depth', 'rank'],
keymap: {
label: 'cat_name',
value: 'cat_name',
depth: 'depth'
},
data: res.data.data
})
console.log(res)
})
}
}
測試案例
配置異步請求數據源 我使用本地 mock、改變一級類目 隨即可以看到二級類目數據發生改變
image.png
image.png