Vue.js: como definir um ID exclusivo para cada instância do componente?


115

Quero criar um componente com Vue.js contendo um rótulo e uma entrada. por exemplo :

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

Como posso definir um ID exclusivo para cada instância do componente?

Obrigado.


Existem vários pacotes / mixins que você pode examinar: vue-ucid , vue-component-id , vue-uniq-ids .
— str

Não tendo visto o comentário anterior antes, também publiquei o plugin Vue vue-unique-id para isso no npm .
— Bernie

Respostas:


175

Cada componente possui um id único que pode ser acessado como 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>

Se você quiser mais controle sobre os ids, você pode, por exemplo, gerá-los dentro de um componente pai.


Observe que o readymétodo foi removido no Vue 2.0 e superior. Fiquei muito confuso quando o readymétodo não estava funcionando. stackoverflow.com/a/40209796/126751
— Brendan Wood

1
... e datadeve ser uma função que retorna um objeto: vuejs.org/v2/guide/components.html#data-Must-Be-a-Function
— arminrosu

3
Infelizmente, isso não funciona no TypeScript, pois this._uidnão é válido. Em vez disso, gere seu id você mesmo, por exemplo public id = uuid4();, consulte uuid4 .
— Erik Vullings

2
Tive que colocar a inicialização no método beforeMount () para ter certeza de que o id foi definido no DOM quando tentei acessá-lo do método mount ().
— Stéphane Gerber,


34

Para o ponto de Nihat (acima): Evan você desaconselhou o uso de _uid: "O vm _uid é reservado para uso interno e é importante mantê-lo privado (e não depender dele no código do usuário) para que possamos manter a flexibilidade de alterá-lo comportamento para possíveis casos de uso futuros. ... Eu sugeriria gerar UIDs você mesmo [usando um módulo, um mixin global, etc.] "

Usar o mixin sugerido neste problema do GitHub para gerar o UID parece uma abordagem melhor:

let uuid = 0;

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

um link para o problema GitHub pertinente seria muito útil aqui
— Damon

1
Aqui está o problema do GitHub em que Evan desaconselha o uso de _id: github.com/vuejs/vue/issues/5886#issuecomment-308625735
— jannej

19

Atualizar: o código gerará um erro se a ._uidpropriedade não existir na instância para que você possa atualizá-lo para usar algo personalizado ou uma nova propriedade de id exclusiva, se fornecida pela Vue.

Embora a resposta de zxzak seja ótima; _uidnão é uma propriedade api publicada. Para evitar uma dor de cabeça caso mude no futuro, você pode atualizar seu código com apenas uma alteração com uma solução de plugin como abaixo.

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");
            }
        });
    }
});

Isso ainda está usando o uid, o que em sua própria resposta reconhece que é desaconselhado. Por favor, não poste respostas que defendam práticas ruins Esta resposta deve ser removida.
— Hybrid web dev

2
Sim, mas caso a API publicada seja alterada / removida, eles terão que alterar apenas um local em todo o código. Na outra resposta, foi por componente. Já enfatizei isso no título.
— Nihat

Além disso, acabei de atualizar o código para que ele gere um erro caso a _uidpropriedade não exista mais.
— Nihat

14

Atualizar

Eu publiquei o vue-unique-id Vue plugin para isso em npm .

Responda

Nenhuma das outras soluções aborda o requisito de ter mais de um elemento de formulário em seu componente. Esta é minha opinião sobre um plugin que se baseia em respostas dadas anteriormente:

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;
  };
});

Isso não depende da _uidpropriedade interna que é reservada para uso interno .

Use-o assim em seu componente:

<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" />

Para produzir algo assim:

<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" />

3
npm i -S lodash.uniqueid

Então em seu código ...

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

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

Desta forma, você não está carregando a biblioteca inteira lodash, ou mesmo salvar a biblioteca inteira para node_modules.


2

No Vue2, use v-bind.

Digamos que tenho um objeto para uma votação

  <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>

O que você deve buscar é v-for="(option, index) in poll.body.options", e usar indexem seu v-bind.
— Warre Buysse

1

Uma abordagem simples que não vi nas respostas é:

<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>

1
O criador do Vue.js diz que você deve evitar o uso de _uid porque é para uso interno e, algum dia, eles podem removê-lo, renomeá-lo ou alterar seu comportamento.
— Omid Sadeghi

1
Obrigado, acho que está correto. Eu atualizei o código com uma solução diferente, esperançosamente ainda simples o suficiente. De qualquer forma, a ideia desse exemplo era usar uma propriedade computada.
— Cristi Draghici

UniqueId de Lodash é a melhor abordagem na minha opinião
— Giorgio Tempesta

1

Se você estiver usando o TypeScript, sem nenhum plug-in, você pode simplesmente adicionar um id estático em seu componente de classe e incrementá-lo no método created (). Cada componente terá um id único (adicione um prefixo de string para evitar colisão com outros componentes que usam a mesma dica)

<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>

0

Este pacote parece ser uma boa solução para o problema subjacente de ter IDs não exclusivos em seu DOM em vários componentes:

vue-uniq-ids

É uma tendência usar componentes. Os componentes são legais, são pequenos, óbvios, fáceis de usar e modulares. Até que se trata da propriedade id.

Alguns atributos de tag HTML requerem o uso de uma propriedade id, como label [for], input [form] e muitos atributos aria- *. E o problema com o id é que ele não é modular. Se várias propriedades de id na página tiverem o mesmo valor, elas podem afetar umas às outras.

O VueUniqIds ajuda você a se livrar desse problema. Ele fornece o conjunto de diretivas relacionadas ao id, cujo valor é modificado automaticamente pela adição de uma string única, mantendo o atributo fácil de ler.


-4

Se o seu uid não for usado por outro componente, tenho uma ideia.

uid: Math.random()

Simples e suficiente.


3
É difícil justificar essa abordagem quando há uma chance real de colisão de id ...
— Shadow

-7

Ele também pode ser alcançado usando este padrão (Vue 2.0 v-bind), então digamos que você tenha uma lista de itens para iterar e queira fornecer alguns ids exclusivos de elementos dom.

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> 

Espero que ajude


8
Você está simplesmente definindo o ID na matriz. Não resolve a questão original de forma alguma.
— arminrosu
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.