iview自定義Tree元件內容
介紹
使用iview框架進行開發的話,一般都有展示樹形結構資料的需求。那麼就用的到其中的Tree元件了。但是其基本架構是滿足不了我們的需求的,基本架構如下:
一般來說一條資料肯定不止展示它的title屬性,我們的需求是展示多個屬性,並且含有多個操作按鈕,具體如下:
這其中得用到 Render 函式來自定義節點顯示內容和互動。
下面就介紹一下Tree元件如何自定義節點內容。
自定義節點內容
先把完整的程式碼貼出來,然後在解釋一波:
<template>
<Card class="album">
<Tree :data="treeData" :load-data="loadData" :render="renderContent"></Tree>
</Card>
</template>
<script>
import { mapActions } from 'vuex'
export default {
name: 'Album',
data () {
return {
treeData: [],
}
},
methods: {
...mapActions ([
'albumCategoryList'
]),
loadData (item, callback) {
let parentId = item.id || 0
let data = []
this.albumCategoryList({
parentId: parentId
}).then((res) => {
if (res.status === 1) {
data = this.getTree(res.fields)
callback(data)
} else {
this.$Notice.error({
title: '錯誤',
desc: res.msg
})
}
}).catch(error => {
this.$Notice.error({
title: '錯誤',
desc: '網路連線錯誤'
})
console.log(error)
})
},
getTree (tree = []) {
let arr = [];
if (tree.length !== 0) {
tree.forEach(item => {
let obj = {};
obj.categoryName = item.categoryName;
obj.id = item.id; // 其他你想要新增的屬性
obj.removed = item.removed; // 其他你想要新增的屬性
obj.rank = item.rank; // 其他你想要新增的屬性
obj.imageUrl = item.imageUrl; // 其他你想要新增的屬性
obj.desc = item.desc; // 其他你想要新增的屬性
obj.parentId = item.parentId; // 其他你想要新增的屬性
if(item.child === 1) {
obj.children = [];
obj.loading = false;
}
arr.push(obj);
});
}
return arr
},
renderContent (h, { root, node, data }) {
return h('span', {
style: {
display: 'inline-block',
width: '100%'
}
}, [
h('span',[
h('Icon', {
style: {
marginRight: '8px'
}
}),
h('span', data.categoryName)
]),
h('span', {
style: {
display: 'inline-block',
float: 'right',
marginRight: '32px'
}
}, [
h('span', {
style: {
display: 'inline-block',
'text-align': 'center',
width: '25px',
marginRight: '40px'
}
}, data.rank),
h('span', {
style: {
display: 'inline-block',
width: '480px',
marginRight: '20px'
}
}, data.imageUrl || ''),
h('Button', {
props: Object.assign({}, {
type: 'primary',
size: 'small',
}),
style: {
marginRight: '8px'
},
on: {
click: () => { this.albumCategoryAdd(data) }
}
}, '新增'),
h('Button', {
props: Object.assign({}, {
type: 'primary',
size: 'small',
}),
style: {
marginRight: '8px'
},
on: {
click: () => { this.albumCategoryEdit(data) }
}
}, '編輯'),
h('Button', {
props: Object.assign({}, {
type: 'error',
size: 'small',
}),
on: {
click: () => { this.changeAlbumCategoryStatus(data.id, data.removed) }
}
}, data.removed === 0 ? '啟用' : '停用' )
])
]);
},
// 頁面載入後 查詢parentID=0 的分類
queryCategoryList (parentId = 0) {
console.log('執行專輯分類queryCategoryList')
this.albumCategoryList({
parentId: parentId
}).then((res) => {
if (res.status === 1) {
// 這裡給節點賦值
this.treeData = this.getTree(res.fields)
} else {
this.$Notice.error({
title: '錯誤',
desc: res.msg
})
}
}).catch(error => {
this.$Notice.error({
title: '錯誤',
desc: '網路連線錯誤'
})
console.log(error)
})
},
},
mounted () {
this.queryCategoryList()
}
}
</script>
<style scoped>
</style>
<Tree :data="treeData" :load-data="loadData" :render="renderContent"></Tree>
看過iview中Tree元件介紹的那就知道:data
是繫結展示的資料的,:load-data
是用於非同步載入子節點的,:render
是用於自定義節點內容的。
先看一下我們的資料結構是啥啊:
我這是axios設定的response攔截器攔截的資料截了個圖,也應該可以看清的吧…
child屬性用來表示此節點是不是有子節點,1表示有,0表示無。別的屬性就不介紹了。
首先,我們開啟頁面的時候應該把所有的頂級父節點即parentId = 0的節點展示出來,這是需要查詢資料庫的,所以在vue生命週期mounted函式中執行了頂級父節點的查詢函式,即:
mounted () {
this.queryCategoryList()
}
// 頁面載入後 查詢parentID=0 的分類
queryCategoryList (parentId = 0) {
console.log('執行專輯分類queryCategoryList')
this.albumCategoryList({
parentId: parentId
}).then((res) => {
if (res.status === 1) {
// 這裡給節點賦值
this.treeData = this.getTree(res.fields)
} else {
this.$Notice.error({
title: '錯誤',
desc: res.msg
})
}
}).catch(error => {
this.$Notice.error({
title: '錯誤',
desc: '網路連線錯誤'
})
console.log(error)
})
},
this.albumCategoryList
是使用axios傳送請求的函式,這裡沒有展示出來,但請求得到的資料結構在上面也展示出來了,應該OK的吧!
this.getTree(res.fields)
這個函式主要是轉換一下資料結構,其中要關注一下,當資料的child屬性為1即其有子節點時,obj.children = []; obj.loading = false;這兩個屬性是必須附上的,否則不會應用非同步載入效果。具體的可看看上面的完整程式碼。
下面看一下自定義節點內容的函式:
renderContent (h, { root, node, data }) {
return h('span', {
style: {
display: 'inline-block',
width: '100%'
}
}, [
h('span',[
h('Icon', {
style: {
marginRight: '8px'
}
}),
h('span', data.categoryName)
]),
h('span', {
style: {
display: 'inline-block',
float: 'right',
marginRight: '32px'
}
}, [
h('span', {
style: {
display: 'inline-block',
'text-align': 'center',
width: '25px',
marginRight: '40px'
}
}, data.rank),
h('span', {
style: {
display: 'inline-block',
width: '480px',
marginRight: '20px'
}
}, data.imageUrl || ''),
h('Button', {
props: Object.assign({}, {
type: 'primary',
size: 'small',
}),
style: {
marginRight: '8px'
},
on: {
click: () => { this.albumCategoryAdd(data) }
}
}, '新增'),
h('Button', {
props: Object.assign({}, {
type: 'primary',
size: 'small',
}),
style: {
marginRight: '8px'
},
on: {
click: () => { this.albumCategoryEdit(data) }
}
}, '編輯'),
h('Button', {
props: Object.assign({}, {
type: 'error',
size: 'small',
}),
on: {
click: () => { this.changeAlbumCategoryStatus(data.id, data.removed) }
}
}, data.removed === 0 ? '啟用' : '停用' )
])
]);
},
這個render函式就不具體解釋了吧,就是根據你定義的treeData陣列中每一條資料來編織你要的樣式。
最後就是非同步載入子節點了:
loadData (item, callback) {
let parentId = item.id || 0
let data = []
this.albumCategoryList({
parentId: parentId
}).then((res) => {
if (res.status === 1) {
data = this.getTree(res.fields)
callback(data)
} else {
this.$Notice.error({
title: '錯誤',
desc: res.msg
})
}
}).catch(error => {
this.$Notice.error({
title: '錯誤',
desc: '網路連線錯誤'
})
console.log(error)
})
},
可以看到這裡邏輯和queryCategoryList
函式差不多,只是查詢條件變成了當前節點的id,表示查詢當前節點的子節點。
PS:上面的完整程式碼是一整個VUE頁面拷貝下來的,除了albumCategoryList
這個axios函式需要自己實現以外