Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

对象排序示例及在 Vue 中的实际应用 #283

Open
yanyue404 opened this issue Sep 30, 2024 · 0 comments
Open

对象排序示例及在 Vue 中的实际应用 #283

yanyue404 opened this issue Sep 30, 2024 · 0 comments

Comments

@yanyue404
Copy link
Owner

yanyue404 commented Sep 30, 2024

前言

在 JavaScript 中,为了保证对象遍历的有序性,我们需要将无序的对象转换为有序的数组。

对象排序 demo

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>对象排序 demo</title>
  </head>
  <body>
    <script>
      const props = {
        pageType: {
          desc: '选择页面类型',
          displayOrder: 2
        },
        pageSetting: {
          type: Object,
          desc: '页面类型配置',
          displayOrder: 3
        },
        appConfig: {
          desc: '全局配置',
          displayOrder: 1
        },
        seo: {
          type: Object,
          desc: 'seo 信息',
          displayOrder: 8
        },
        share: {
          type: Object,
          desc: '分享配置',
          displayOrder: 4
        },
        wxOauth: {
          type: Object,
          desc: '微信授权',
          displayOrder: 5
        },
        schema: { type: 'SCHEMA', name: 'app', displayOrder: 6 },
        assets: {
          type: Object,
          desc: 'js&css',
          displayOrder: 9
        },
        htmlStyle: {
          type: Array,
          desc: '设置html的样式',
          displayOrder: 7
        },
        other: {
          type: Object,
          desc: '其他配置',
          displayOrder: 10
        }
      }

      console.log('默认顺序', Object.keys(props))

      console.log('sort 排序', Object.keys(props).sort())

      console.log(
        '自定义对象排序',
        Object.keys(props).sort(function (a, b) {
          return props[a].displayOrder - props[b].displayOrder
        })
      )

      const toArraySort = (obj, sortKey) => {
        const map = new Map()
        const sortKeys = Object.keys(obj).sort(function (a, b) {
          return obj[a][sortKey] - obj[b][sortKey]
        })

        sortKeys.forEach((prop, index) => {
          map.set(index, {
            key: prop,
            value: obj[prop]
          })
        })
        return Array.from(map.entries())
      }

      console.log('自定义对象排序的数组 1', toArraySort(props, 'displayOrder'))

      const toSortByArray = (obj, referArr) => {
        const map = new Map()
        const sortKeys = Object.keys(obj).sort(function (a, b) {
          const indexA = referArr.indexOf(a)
          const indexB = referArr.indexOf(b)

          // 当元素不在 referArr 时,将其索引设置为数组长度,放到后面
          const orderA = indexA === -1 ? referArr.length : indexA
          const orderB = indexB === -1 ? referArr.length : indexB
          return orderA - orderB // 升序排序
        })

        sortKeys.forEach((prop, index) => {
          map.set(index, {
            key: prop,
            value: obj[prop]
          })
        })
        return Array.from(map.entries())
      }

      console.log(
        '自定义对象排序的数组 2',
        toSortByArray(props, [
          'appConfig',
          'seo',
          'share',
          'pageType',
          'pageSetting'
        ])
      )
    </script>
  </body>
</html>

在 Vue 中遍历使用

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vue Example</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@3"></script>
    <style>
      body {
        font-family: Arial, sans-serif;
        margin: 20px;
      }
      h6 {
        margin: 10px 0;
      }
      .obj-wrap {
        border: 1px #ccc solid;
        border-radius: 10px;
        padding: 10px;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <div class="obj-wrap">
        <object-field
          :properties="schemaProperty"
          v-model="moduleRef"
        ></object-field>
      </div>
    </div>

    <script>
      const ObjectField = {
        props: {
          properties: {
            type: Object,
            required: true
          },
          modelValue: {
            type: Object,
            required: true
          }
        },
        emits: ['update:modelValue'],
        computed: {
          sortedProperties() {
            return Object.entries(this.properties).map(([key, property]) => ({
              key,
              property,
              value: this.modelValue[key]
            }))
          }
        },
        methods: {
          getInputType(type) {
            return type === 'String' ? 'text' : type
          },
          handleInput(key, value) {
            // 这里需要确保我们只更新当前字段
            this.$emit('update:modelValue', {
              ...this.modelValue, // 创建一个新对象
              [key]: value // 更新当前字段
            })
          }
        },
        template: `
                <div>
                    <div v-for="({ key, property, value }, index) in sortedProperties" :key="key">
                        <h6>{{ property.desc }}</h6>
                        <div v-if="property.type !== 'Object'">
                            <input
                                :type="getInputType(property.type)"
                                :value="value"
                                @input="handleInput(key, $event.target.value)"
                                :placeholder="\`请输入\${property.desc}字段\`"
                            />
                        </div>
                        <div class="obj-wrap" v-if="property.type === 'Object'">
                            <object-field
                                :properties="property.default()"
                                :modelValue="modelValue[key]"
                                @update:modelValue="handleInput(key, $event)"
                            ></object-field>
                        </div>
                    </div>
                </div>
            `
      }

      const app = Vue.createApp({
        components: {
          'object-field': ObjectField
        },
        data() {
          return {
            schemaKey: 'exampleSchema',
            schemaProperty: {
              name: { desc: '姓名', type: 'String' },
              age: { desc: '年龄', type: 'Number' },
              email: { desc: '电子邮件', type: 'String' },
              address: {
                desc: '地址',
                type: 'Object',
                default: () => {
                  return {
                    addressType: { desc: '地址类型', type: 'String' },
                    detail: { desc: '详细地址', type: 'String' }
                  }
                }
              }
            },
            moduleRef: {
              name: 'yanyue404',
              age: '18',
              email: '[email protected]',
              address: {
                addressType: '家庭住址',
                detail: '北京市昌平区'
              }
            }
          }
        },
        methods: {
          updateModel({ key, value }) {
            this.moduleRef[key] = value // May be redundant now
          }
        }
      })

      app.component('object-field', ObjectField)

      app.mount('#app')
    </script>
  </body>
</html>

参考

@yanyue404 yanyue404 changed the title Javascript 中的对象排序问题 对象排序示例及在 Vue 中的实际应用 Sep 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant