【Vue实用组件】排序布局

这是一个关于Vue2的自定义组件`SortLayout`的介绍,该组件允许根据动态条件改变元素的顺序和显隐状态,适用于复杂表单场景。通过`tag`属性设置包裹元素类型,`sort`属性接受数组或函数来定义元素的排序逻辑。示例展示了如何使用`SortLayout`进行动态排序,包括基于数组和自定义排序方法两种方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

排序布局

  • 简述:使用此组件可以灵活改变插入元素中的顺序和显隐状态。
  • 使用场景:需要根据动态条件渲染的复杂组件场景。例如表单区域中按条件渲染指定的表单交互项组件。

组件源码 (Vue2)

<script>
/**
 *  排序布局
 *  @param  {String}          tag     包囊元素标签
 *  @param  {Object}          attrs   包囊元素属性
 *  @param  {Array|Function}  sorts   元素插入顺序 ( Array[String|VNode] | Function: 动态顺序,传参: (slots),返回 Array[String|VNode] )
 *  @param  {String}          sortBy  排序来源 ( 'key': 默认值,根据 slots.default 内含 key 的元素排序 | 'slot': 根据 slots 名称排序 | String: 根据元素绑定的指定属性排序 | null: 不使用排序 )
 */
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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值