排序布局
- 简述:使用此组件可以灵活改变插入元素中的顺序和显隐状态。
- 使用场景:需要根据动态条件渲染的复杂组件场景。例如表单区域中按条件渲染指定的表单交互项组件。
组件源码 (Vue2)
<script>
export default {
name: 'SortLayout',
functional: true,
inheritAttrs: false,
props: {
tag: { type: String, default: 'span' },
attrs: { type: Object, default: void 0 },
sorts: { type: [Array, Function], default: void 0 },
sortBy: { type: String, default: 'key' }
},
render(h, { props: { tag, attrs, sorts, sortBy }, data, slots, children }) {
if (tag == 'span') (data.staticStyle ||= {}).display ||= 'contents'
if (attrs && attrs.class) data.class = [].concat(attrs.class, data.class || []), delete attrs.class
if (attrs && attrs.style) data.style = [].concat(attrs.style, data.style || []), delete attrs.style
data.attrs = attrs
if (sortBy != null) {
let isSame = (obj, val) => !!obj && Object.prototype.hasOwnProperty.call(obj, sortBy) && obj[sortBy] === val
children = [], slots = slots(), typeof sorts == 'function' && (sorts = sorts(slots))
Array.isArray(sorts) && sorts.forEach(item => {
if (typeof item == 'string' || typeof item == 'number') {
if (sortBy == 'slot') {
for (let i = 0, l = slots[item]?.length || 0; i < l; i++) {
let slot = slots[item][i]
slot.key ??= i > 0 ? `${item}_${i}` : item
children.push(slot)
}
} else {
for (let n = 0, i = 0, l = slots.default?.length || 0; i < l; i++) {
let slot = slots.default[i]
if (sortBy == 'key' ? slot.key === item : isSame(slot.componentOptions?.propsData, item) || isSame(slot.data?.attrs, item)) {
slot.key ??= n > 0 ? `${item}_${n}` : item
children.push(slot), n++
}
}
}
} else if (typeof item == 'object' && item != null && slots.default?.includes(item)) {
children.push(item)
}
})
}
return h(tag, data, children)
}
}
</script>
使用示例
<template>
<div>
<h3>Demo 1: Sort by random keys.</h3>
<sort-layout tag="div" sortBy="key" :sorts="sort1" :attrs="{ id: 'demo1', title: 'sort by key' }" class="demo-div">
<div key="1">A</div>
<div key="2">B</div>
<div key="3">C</div>
<div key="4">D</div>
<div :key="4">E</div>
<div :key="5">F</div>
<div>Default</div>
</sort-layout>
<h3>Demo 2: Sort by this <button @click="sort2Update">button</button></h3>
<sort-layout tag="ul" sortBy="slot" :sorts="sort2" :attrs="{ id: 'demo2', title: 'sort by slot' }" class="demo-ul">
<template slot="s1">
<li>1.1</li>
<li>1.2</li>
<li>1.3</li>
</template>
<li slot="s2">2</li>
<li slot="s3">3</li>
<li slot="s4">4</li>
<li>Default</li>
</sort-layout>
<h3>Demo 3: Sort by method:data-name.</h3>
<sort-layout tag="div" sortBy="data-name" :sorts="sort3Method" :attrs="{ id: 'demo3' }" style="background: #eee;">
<component v-for="i in 6" :key="i" :is="`h${i}`" :data-name="`h${i}`">H{{ i }}</component>
</sort-layout>
<h3>Demo 4: Sort by method:VNode.</h3>
<sort-layout tag="div" :sorts="sort4Method" :attrs="{ id: 'demo4' }" style="background: #ddd;">
<p v-for="i in 6" :key="i">P{{ i }}</p>
</sort-layout>
</div>
</template>
<script>
import SortLayout from '@/components/SortLayout'
export default {
components: { SortLayout },
data() {
return {
sort1: [],
sort2: ['s1', 's2', 's3', 's4']
}
},
mounted() {
this.sort1Init()
},
methods: {
sort1Init() {
const sort1 = [
['3', '2', 5, 4],
['1', '5', '4', 5, 4],
[6, 5, 4, 3, 2, 1],
['1', '2', '3', '4', 4, 5]
]
setInterval(() => { this.sort1 = sort1[Math.floor(Math.random() * sort1.length)] }, 3000)
},
sort2Update() {
this.sort2.push(...this.sort2.splice(0, 1))
},
sort3Method(slots) {
return ['h3', 'h5', 'h6', 'h2', 'h4', slots.default[0]]
},
sort4Method(slots) {
return slots.default.sort(() => Math.random() > 0.5 ? 1 : -1)
}
}
}
</script>