Vue.js: Làm cách nào để thiết lập một ID duy nhất cho từng cá thể thành phần?


115

Tôi muốn tạo một thành phần với Vue.js có chứa nhãn và đầu vào. ví dụ :

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

Làm cách nào để đặt một ID duy nhất cho từng phiên bản thành phần?

Cảm ơn bạn.


Có một số gói / mixin mà bạn có thể xem xét: vue-ucid , vue-component-id , vue-uniq-id .
str

Chưa từng thấy nhận xét trước đây, tôi cũng đã xuất bản plugin Vue-unique-id Vue cho điều này trên npm .
bernie

Câu trả lời:


175

Mỗi thành phần có một id duy nhất có thể được truy cập như 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>

Ví dụ, nếu bạn muốn kiểm soát nhiều hơn các id, hãy tạo chúng bên trong một thành phần mẹ.


Lưu ý rằng readyphương thức này đã bị xóa trong Vue 2.0 trở lên. Tôi đã rất bối rối khi readyphương thức này không thực thi. stackoverflow.com/a/40209796/126751
Brendan Wood

1
... và dataphải là một hàm trả về một đối tượng: vuejs.org/v2/guide/components.html#data-Must-Be-a-Function
arminrosu

3
Thật không may, điều này không hoạt động trong TypeScript, vì this._uidnó không hợp lệ. Thay vào đó, hãy tự tạo id của bạn, ví dụ: public id = uuid4();xem uuid4 .
Erik Vullings

2
Tôi phải đặt phần khởi tạo trong phương thức beforeMount () để đảm bảo rằng id đã được đặt trong DOM khi tôi cố gắng truy cập nó từ phương thức mount ().
Stéphane Gerber


34

Theo quan điểm của Nihat (ở trên): Evan Bạn đã khuyên không nên sử dụng _uid: "vm _uid được dành riêng cho mục đích sử dụng nội bộ và điều quan trọng là phải giữ nó ở chế độ riêng tư (và không dựa vào nó trong mã người dùng) để chúng tôi có thể linh hoạt thay đổi nó hành vi cho các trường hợp sử dụng tiềm năng trong tương lai. ... Tôi khuyên bạn nên tự tạo UID [sử dụng một mô-đun, một tổng hợp chung, v.v.] "

Sử dụng mixin được đề xuất trong vấn đề GitHub này để tạo UID có vẻ là một cách tiếp cận tốt hơn:

let uuid = 0;

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

một liên kết đến các vấn đề GitHub thích hợp sẽ rất hữu ích ở đây
Damon

1
Đây là sự cố GitHub mà Evan khuyên không nên sử dụng _id: github.com/vuejs/vue/issues/5886#issuecomment-308625735
jannej

19

Cập nhật: Mã sẽ gặp lỗi nếu thuộc ._uidtính không tồn tại trong phiên bản để bạn có thể cập nhật nó để sử dụng thuộc tính id duy nhất tùy chỉnh hoặc mới nếu được Vue cung cấp.

Mặc dù câu trả lời của zxzak là tuyệt vời; _uidkhông phải là tài sản api đã xuất bản. Để đỡ đau đầu trong trường hợp nó thay đổi trong tương lai, bạn có thể cập nhật mã của mình chỉ bằng một lần thay đổi với giải pháp plugin như bên dưới.

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

Điều này vẫn đang sử dụng uid, mà trong câu trả lời của riêng bạn thừa nhận là không nên. Vui lòng không đăng câu trả lời ủng hộ các hành vi xấu. Câu trả lời này nên được loại bỏ.
web kết hợp

2
Có nhưng trong trường hợp api đã xuất bản bị thay đổi / xóa, họ sẽ chỉ phải thay đổi một vị trí trong toàn bộ mã. Trong câu trả lời khác, đó là mỗi thành phần. Tôi đã nhấn mạnh điều đó trong tiêu đề.
Nihat

Ngoài ra, tôi vừa cập nhật mã để nó sẽ xuất hiện lỗi trong trường hợp thuộc _uidtính không tồn tại nữa.
Nihat

14

Cập nhật

Tôi đã xuất bản plugin vue-unique-id Vue cho cái này vào npm .

Câu trả lời

Không có giải pháp nào khác giải quyết yêu cầu có nhiều hơn một phần tử biểu mẫu trong thành phần của bạn. Đây là bước đi của tôi về một plugin được xây dựng dựa trên các câu trả lời đã cho trước đó:

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

Điều này không phụ thuộc vào thuộc tính nội bộ _uidđược dành cho sử dụng nội bộ .

Sử dụng nó như thế này trong thành phần của bạn:

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

Để tạo ra một cái gì đó như thế này:

<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

Sau đó, trong mã của bạn ...

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

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

Bằng cách này, bạn sẽ không tải toàn bộ thư viện lodash hoặc thậm chí lưu toàn bộ thư viện vào node_modules.


2

Trong Vue2, sử dụng v-bind.

Giả sử tôi có một đối tượng cho một cuộc thăm dò

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

Những gì bạn nên đi là v-for="(option, index) in poll.body.options"và sử dụng indextrong bạn v-bind.
Warre Buysse

1

Một cách tiếp cận đơn giản mà tôi chưa thấy trong các câu trả lời là:

<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
Người tạo ra Vue.js nói rằng bạn nên tránh sử dụng _uid vì nó để sử dụng nội bộ và một ngày nào đó họ có thể xóa nó hoặc đổi tên nó hoặc thay đổi hành vi của nó.
Omid Sadeghi

1
Cảm ơn, tôi nghĩ điều đó là chính xác. Tôi đã cập nhật mã bằng một giải pháp khác, hy vọng vẫn đủ đơn giản. Dù sao, ý tưởng của ví dụ này là sử dụng một thuộc tính được tính toán.
Cristi Draghici

UNIQUEID từ lodash là cách tiếp cận tốt nhất theo ý kiến của tôi
Giorgio Tempesta

1

Nếu bạn đang sử dụng TypeScript mà không có bất kỳ plugin nào, bạn có thể chỉ cần thêm một id tĩnh vào thành phần lớp của mình và tăng nó trong phương thức create (). Mỗi thành phần sẽ có một id duy nhất (thêm tiền tố chuỗi để tránh va chạm với các thành phần khác sử dụng cùng một mẹo)

<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

Gói này dường như là một giải pháp tốt cho vấn đề cơ bản là có các ID không phải là duy nhất trong DOM của bạn trên nhiều thành phần:

vue-uniq-id

Đó là một xu hướng sử dụng các thành phần. Các thành phần rất tuyệt, chúng nhỏ, rõ ràng, dễ sử dụng và mô-đun. Bỏ nó đến thuộc tính id.

Một số thuộc tính thẻ HTML yêu cầu sử dụng thuộc tính id, như nhãn [for], input [form] và nhiều thuộc tính aria- *. Và vấn đề với id là nó không phải là mô-đun. Nếu một số thuộc tính id trên trang sẽ có cùng giá trị, chúng có thể ảnh hưởng lẫn nhau.

VueUniqIds giúp bạn thoát khỏi vấn đề này. Nó cung cấp tập hợp các chỉ thị liên quan đến id mà giá trị được tự động sửa đổi bằng cách thêm chuỗi duy nhất trong khi vẫn giữ cho phần đính kèm dễ đọc.


-4

Nếu uid của bạn không được sử dụng bởi thành phần khác, tôi có một ý tưởng.

uid: Math.random()

Đơn giản và đủ.


3
Thật khó để biện minh cho cách tiếp cận này khi có khả năng xảy ra va chạm id thực sự ...
Shadow

-7

Nó cũng có thể đạt được bằng cách sử dụng mẫu này (Vue 2.0 v-bind), vì vậy, giả sử bạn có một danh sách các mục để lặp lại và bạn muốn cung cấp một số id không có phần tử 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> 

Hy vọng nó giúp


8
Bạn chỉ cần xác định ID trong mảng. Không giải quyết được câu hỏi ban đầu ở tất cả.
arminrosu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.