Подумав два дня, я был готов реализовать управление деревом на основе vue по образцу ant-design-vue. Он в основном использует идею рекурсивных компонентов Vue и использование полей ввода типа CheckBox.
нужно
- Возможность генерировать каталог дерева из входящих данных Json.
- Возможность инициализировать выбранные узлы.
- Узлы можно выбирать вручную, и, наконец, все выбранные узлы можно распечатать.
- Возможность отключать узлы при инициализации.
- Возможность свернуть дерево каталогов.
- Измените собственный стиль CheckBox.
Пример скриншота
Завершенный элемент управления деревом выглядит следующим образом: нажмите, чтобы получить выбранный ключ узла, и все выбранные узлы появятся во всплывающем окне:
Рука об руку
Понимание рекурсивных компонентов Vue
В документации vue (Talent.v UE JS.org/V2/expensive/co…
- Компоненты имеют атрибут имени
- Рекурсивные вызовы должны быть условными
Базовый элемент управления деревом tree.vue создается в соответствии с приведенными выше инструкциями:
Глобальные переменные: global.js
При написании компонента для получения содержимого узла обнаруживается, что, поскольку он является рекурсивным компонентом, нелегко выбрать узел на каждом уровне. Поэтому создайте здесь глобальную переменную global.js для записи всех выбранных узлов. Также легко удалять и присоединять узлы. По умолчанию выбраны следующие узлы:
const nodes = ['1', '1-1', '1-1-2', '1-2-2']
export default {
nodes
}
После написания его нужно смонтировать на main.js.
import global from 'common/js/global'
Vue.prototype.$global = global
Базовый компонент (рекурсивный компонент): tree.vue
Примечание: нет необходимости использовать атрибут компонентов, чтобы объявить себя здесь.С помощью атрибута имени вы можете вызвать значение имени компонента непосредственно в шаблоне.
<template>
<ul class="ul-wrapper"> <!-- 包裹层-->
<li v-for="item in list" :key="item.key"> <!-- 遍历-->
<div> <!-- 是否展开图标-->
<img class="icon"
v-show="item.children"
@click="changeShow"
:src="require(`../common/images/${imgUrl}`)"
> <!-- CheckBox-->
<input
type="checkbox"
:name="item.key"
@click="clickbox"
:checked="isChecked(item.key)"
:disabled="item.disabled"
>
<div class="checkbox-title">{{item.title}}</div> <!-- CheckBox内容-->
</div>
<tree v-if="showChildren" :list="item.children"></tree> <!-- 遍历children-->
</li>
</ul>
</template>
<script type='text/ecmascript-6'>
export default {
name: 'tree',
props: {
list: { // 所有树节点
type: Array,
default: () => {
return []
}
}
},
data () {
return {
showChildren: true // 是否展开根目录
}
},
computed: { // computed属性计算展开图标
imgUrl () {
return this.showChildren ? 'down.png' : 'right.png'
}
},
methods: {
clickbox (e) { // 点击CheckBox时需要加入或删除已选中this.$global.nodes的节点数组中
const checked = e.target.checked
const key = e.target.name
const nodes = this.$global.nodes // this.$global.nodes是全局变量,便于递归组件记录选中节点
if (checked) {
if (!nodes.includes(key)) {
this.$global.nodes.push(key)
}
} else {
this.$global.nodes = nodes.filter((item) => {
return key !== item
})
}
},
changeShow () { // 点击是否展开根目录,当前状态取反即可
this.showChildren = !this.showChildren
},
isChecked (key) { // 查看是否已经存在于选中节点中
return this.$global.nodes.includes(key)
}
}
}
</script>
<style lang="stylus">
.ul-wrapper // ul包裹层,每层需要向右偏移30px
margin 10px 30px 0
.checkbox-title, .icon
display inline-block
vertical-align middle
.icon
margin-left -20px
height 18px
width 18px
input[type="checkbox"] // CheckBox样式修改
position relative
display inline-block
vertical-align middle
padding 0
margin-right 5px
height 18px
width 18px
border 1px solid #ccc
border-radius 3px
input[type="checkbox"]:checked::before // CheckBox选中状态时样式修改
position absolute
top 0
left 0
padding-left 2px
content: "\2713";
height 15px
width 13px
font-size 12px
font-weight: bold;
background #1296db
color #fff
border-radius 3px
border 0
input[type="checkbox"]:disabled::before // CheckBox禁用状态时样式修改
position absolute
top 0
left 0
padding-left 2px
content: "";
height 15px
width 13px
font-size 12px
font-weight: bold;
background #ccc
color #fff
border-radius 3px
border 0
</style>
Компонент приложения tree-apply.vue
<template>
<div class="tree-wrapper">
<div class="btn" @click="showNodes">
点击获取选中节点key
</div>
<Tree :list="treeData"></Tree>
</div>
</template>
<script type='text/ecmascript-6'>
import Tree from 'base/tree'
export default {
data () {
return {
treeData: [] // 全部节点
}
},
created () {
this.getData()
},
methods: {
getData () {
this.axios.get('/tree').then((res) => { // 获取mock数据
this.treeData = res.data
})
},
showNodes () {
alert(this.$global.nodes)
}
},
components: {
Tree
}
}
</script>
<style lang="stylus">
.btn
margin 20px
text-align center
</style>
макет данных tree.json
Здесь используется метод имитации данных, конкретное использование mock упоминается в моей последней статье «better-scroll реализует компонент карусели»:blog.CSDN.net/QQ_39083496…
- Отключение CheckBox определяется в соответствии с «отключено»: «истинно».
- title (обязательно) — отображаемое имя ярлыка.
- Ключ (must) — это настоящее ключевое слово, под которым понимается обязательное поле для окончательной отправки.
[{
"title": "1",
"key": "1",
"children": [
{
"title": "1-1",
"key": "1-1",
"children": [
{ "title": "1-1-1", "key": "1-1-1" },
{ "title": "1-1-2", "key": "1-1-2" },
{ "title": "1-1-3", "key": "1-1-3" }
]
},
{
"title": "1-2",
"key": "1-2",
"children": [
{ "title": "1-2-1", "key": "1-2-1" },
{ "title": "1-2-2", "key": "1-2-2" },
{ "title": "1-2-3", "key": "1-2-3" }
]
},
{
"title": "1-3",
"key": "1-3"
}
]
},
{
"title": "2",
"key": "2",
"disabled": "true",
"children": [
{ "title": "2-1", "key": "2-1" },
{ "title": "2-2", "key": "2-2" },
{ "title": "2-3", "key": "2-3" }
]
},
{
"title": "3",
"key": "3"
}]
интерфейс:
const Mock = require('mockjs')
Mock.mock('/tree', 'get', require('./json/tree.json'))
Суммировать
На этом генерация элемента управления "дерево" завершена, и требования выполнены. Если вы не можете понять приведенный выше фрагмент кода, вы можете найти исходный код на моем github. Добро пожаловать в гости, добро пожаловать в Star~
GitHub.com/GE Involvement-жидкий аммиак/V…