【问题标题】:Vue.js : How to set a unique ID for each component instance?Vue.js:如何为每个组件实例设置唯一 ID?
【发布时间】:2016-04-29 07:10:30
【问题描述】:

我想用 Vue.js 创建一个包含标签和输入的组件。例如:

<label for="inputId">Label text</label>
<input id="inputId" type="text" />

如何为每个组件实例设置唯一 ID?

【问题讨论】:

标签: vue.js


【解决方案1】:

每个组件都有一个唯一的 ID,可以通过 this._uid 访问。

<template>
  <div>
    <label :for="id">Label text for {{id}}</label>
    <input :id="id" type="text" />
  </div>
</template>

<script>
export default {
  data () {
    return {
      id: null
    }
  }, 
  mounted () {
    this.id = this._uid
  }
}
</script>

如果您想对 id 进行更多控制,例如,可以在父组件中生成它们。

【讨论】:

【解决方案2】:

至 Nihat 的观点(上图):Evan You 建议不要使用 _uid:“vm _uid 保留供内部使用,重要的是保持私有(而不是在用户代码中依赖它),以便我们保持灵活性改变其行为以适应未来的潜在用例。...我建议自己生成 UID [使用模块、全局 mixin 等]”

使用 this GitHub issue 中建议的 mixin 来生成 UID 似乎是一种更好的方法:

let uuid = 0;

export default {
  beforeCreate() {
    this.uuid = uuid.toString();
    uuid += 1;
  },
};

【讨论】:

【解决方案3】:

更新: 如果实例中不存在 ._uid 属性,代码将抛出错误,以便您可以更新它以使用 Vue 提供的自定义或新的唯一 id 属性。

虽然zxzak的回答很棒; _uid 不是已发布的 api 属性。为了避免将来发生变化时头疼,您可以使用如下插件解决方案,只需一次更改即可更新您的代码。

Vue.use({
    install: function(Vue, options) {
        Object.defineProperty(Vue.prototype, "uniqId", {
            get: function uniqId() {
                if ('_uid' in this) {
                   return this._uid;
                }
                throw new Error("_uid property does not exist");
            }
        });
    }
});

【讨论】:

  • 这仍在使用 uid,在您自己的回答中承认不建议这样做。请不要发布提倡不良做法的答案。这个答案应该被删除。
  • 是的,但是如果发布的 api 被更改/删除,他们将只需要更改整个代码中的一个地方。在另一个答案中,它是每个组件。我已经在标题中强调了这一点。
  • 另外,我刚刚更新了代码,以便在 _uid 属性不再存在时会抛出错误。
【解决方案4】:

更新

我发布了vue-unique-id Vue plugin for this on npm

回答

其他解决方案都不能满足组件中包含多个表单元素的要求。这是我对基于先前给出的答案的插件的看法:

Vue.use((Vue) => {
  // Assign a unique id to each component
  let uuid = 0;
  Vue.mixin({
    beforeCreate: function() {
      this.uuid = uuid.toString();
      uuid += 1;
    },
  });

  // Generate a component-scoped id
  Vue.prototype.$id = function(id) {
    return "uid-" + this.uuid + "-" + id;
  };
});

这不依赖于内部的_uid 属性,即reserved for internal use

在你的组件中像这样使用它:

<label :for="$id('field1')">Field 1</label>
<input :id="$id('field1')" type="text" />

<label :for="$id('field2')">Field 2</label>
<input :id="$id('field2')" type="text" />

要产生这样的东西:

<label for="uid-42-field1">Field 1</label>
<input id="uid-42-field1" type="text" />

<label for="uid-42-field2">Field 2</label>
<input id="uid-42-field2" type="text" />

【讨论】:

  • 请注意,这个插件似乎不适用于 Vue3
【解决方案5】:
npm i -S lodash.uniqueid

然后在你的代码中...

<script>
  const uniqueId = require('lodash.uniqueid')

  export default {
    data () {
      return {
        id: ''
      }
    },
    mounted () {
       this.id = uniqueId()
    }
  }
</script>

这样您就不会加载整个 lodash 库,甚至不会将整个库保存到 node_modules

【讨论】:

    【解决方案6】:

    如果你使用 TypeScript,没有任何插件,你可以简单地在你的类组件中添加一个静态 id 并在 created() 方法中增加它。每个组件都会有一个唯一的 id(添加字符串前缀以避免与使用相同提示的其他组件发生冲突)

    <template>
      <div>
        <label :for="id">Label text for {{id}}</label>
        <input :id="id" type="text" />
      </div>
    </template>
    
    <script lang="ts">
      ...
      @Component
      export default class MyComponent extends Vue {
        private id!: string;
        private static componentId = 0;
        ...
        created() {
          MyComponent.componentId += 1;
          this.id = `my-component-${MyComponent.componentId}`;
        }
    </script>
    

    【讨论】:

    • 定义 Vue 组件的非基于class 的语法的等价物是什么?例如使用 `export default defineComponent({ created() { ... }, ... });
    【解决方案7】:

    我在回复中没有看到的一个简单方法是:

    <template>
      <div>
        <label :for="id">Label text for {{id}}</label>
        <input :id="id" type="text" />
      </div>
    </template>
    
    <script>
    import uniqueId from 'lodash-es/uniqueId'
    
    export default {
      computed: {
        id () {
          # return this._uid
          return uniqueId('id')
        }
      }
    }
    </script>
    

    【讨论】:

    • Vue.js 的创建者说你应该避免使用 _uid,因为它是供内部使用的,有一天他们可能会删除它或重命名它或改变它的行为。
    • 谢谢,我认为这是正确的。我已经用不同的解决方案更新了代码,希望仍然足够简单。无论如何,这个例子的想法是使用计算属性。
    • lodash 的 uniqueId 在我看来是最好的方法
    【解决方案8】:

    在 Vue2 中,使用v-bind

    假设我有一个投票对象

    <div class="options" v-for="option in poll.body.options">
      <div class="poll-item">
        <label v-bind:for="option._id" v-bind:style="{color: option.color}">
          {{option.text}}
        </label>
        <input type="radio" v-model="picked" v-bind:value="option._id" v-bind:id="option._id">
      </div>
    </div>
    

    【讨论】:

    • 你应该使用v-for="(option, index) in poll.body.options",并在你的v-bind中使用index
    【解决方案9】:

    这似乎对我在 nuxtjs 中使用有用

    https://www.npmjs.com/package/uuid

    生成的输出示例: 元件:47bfe557-d75f-455c-9a37-85b7935b297b

    package.json

    "dependencies": {    
        "uuid": "^8.3.2"
     },
    

    在子组件上,可能不是最好的方法,但似乎可以工作

    ...

    <ComponentName v-if="element" />
    

    ...

    import { v4 as uuidv4 } from 'uuid';
    

    ...

    data() {
      return {
        element: null,
      }
    }
    

    ...

    mounted() {
      this.element = uuidv4();
    }
    

    【讨论】:

      【解决方案10】:

      这个包似乎是解决 DOM 中跨多个组件的非唯一 ID 的潜在问题的一个很好的解决方案:

      vue-uniq-ids

      使用组件是一种趋势。组件很酷,它们很小、很明显、易于使用和模块化。直到涉及到 id 属性。

      一些 HTML 标签属性需要使用 id 属性,例如 label[for]、input[form] 和许多 aria-* 属性。 id 的问题在于它不是模块化的。如果页面上的多个 id 属性具有相同的值,它们可以相互影响。

      VueUniqIds 可以帮助您摆脱这个问题。它提供了一组与id相关的指令,通过添加唯一字符串自动修改值,同时保持属性易于阅读。

      【讨论】:

        【解决方案11】:

        使用这个:this.$options._scopeId - 与“样式范围”部分中使用的标识符相同:

        【讨论】:

          【解决方案12】:

          这似乎对我有用 https://www.npmjs.com/package/uuid

          生成的输出示例: 元件:47bfe557-d75f-455c-9a37-85b7935b297b

          package.json

          "dependencies": {    
              "uuid": "^8.3.2"
           },
          

          组件.vue

          v-if="element"
          

          ...

          import { v4 as uuidv4 } from 'uuid';
          

          ...

          data() {
            return {
              element: null,
            }
          }
          

          ...

          mounted() {
            this.element = uuidv4();
          }
          

          【讨论】:

            【解决方案13】:

            我发现最简单的方法是通过全局 mixin 手动创建 UUID (uuid package)。这样您就不会依赖任何可能在未来发生变化或被弃用的东西,例如 this._uid

            您首先必须安装uuid 包:

            npm i uuid
            

            然后,在您的 main.js 文件中创建一个全局 mixin:

            // rest of imports
            
            import { v4 as uuidv4 } from 'uuid';
            
            const app = Vue.createApp(App);
            
            app.mixin({
                data() {
                    return {
                        componentId: uuidv4()
                    }
                },
            });
            
            app.use(store).use(router).mount('#app');
            

            下面是如何在组件中使用它:

            <template>
               <div>
                  <h1>{{ componentId }}</h1>
                  <button @click="printId()">click me for componentId.</button>
               </div>
            </template>
            
            <script>
            export default {
               methods: {
                  printId: function() {
                     console.log(this.componentId);
                  }
               }
            }
            </script>
            

            【讨论】:

              【解决方案14】:

              根据MDN,您可以只进行隐式label 绑定。

              <label>
                Label text
                <input type="text" />
              </label>
              

              这样你甚至不需要分配一个 id。

              【讨论】:

                【解决方案15】:

                如果你的uid没有被其他组件使用,我有个主意。

                uid: Math.random()

                简单又足够。

                【讨论】:

                • 当确实有可能发生 id 冲突时,很难证明这种方法的合理性......
                【解决方案16】:

                也可以使用这种模式(Vue 2.0 v-bind)来实现,所以假设你有一个要迭代的项目列表,并且你想给一些 dom 元素 uninque id。

                new Vue({
                
                  el:body,
                  data: {
                     myElementIds : [1,2,3,4,5,6,8]
                   }
                })
                

                HTML

                <div v-for="id in myElementIds">
                    <label v-bind:for="id">Label text for {{id}}</label>
                    <input v-bind:id="id" type="text" />
                <div> 
                

                希望对你有帮助

                【讨论】:

                • 您只是在数组中定义 ID。根本没有解决原来的问题。
                猜你喜欢
                • 2018-11-07
                • 2019-12-19
                • 1970-01-01
                • 2017-09-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-11-20
                • 1970-01-01
                相关资源
                最近更新 更多