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.

PierreB
fonte
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.

zxzak
fonte
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;
  },
};
espinheiro
fonte
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");
            }
        });
    }
});
Nihat
fonte
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" />
Bernie
fonte
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.

meconroy
fonte
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>
趙曉明
fonte
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>
Cristi Draghici
fonte
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>
JMess
fonte
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.

tryforceful
fonte
-4

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

uid: Math.random()

Simples e suficiente.

YinPeng.Wei
fonte
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

pitaside
fonte
8
Você está simplesmente definindo o ID na matriz. Não resolve a questão original de forma alguma.
arminrosu