我想用 Vue.js 创建一个包含 label
和 input
的组件。例如 :
<label for="inputId">Label text</label>
<input id="inputId" type="text" />
如何为每个组件实例设置唯一 ID?
每个组件都有一个唯一的 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 进行更多控制,可以在父组件中生成它们。
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;
},
};
更新:如果实例中不存在 ._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
属性不再存在的情况下引发错误。
更新
我发布了 vue-unique-id Vue plugin for this on npm。
回答
其他解决方案都没有解决组件中包含多个表单元素的要求。这是我对基于先前给出的答案的插件的看法:
Vue.use((Vue) => {
// Assign a unique id to each component
let uidCounter = 0;
Vue.mixin({
beforeCreate: function() {
this.uidCounter = uidCounter.toString();
uidCounter += 1;
},
});
// Generate a component-scoped id
Vue.prototype.$id = function(id) {
return "uid-" + this.uidCounter + "-" + id;
};
});
这不依赖于 reserved for internal use 的内部 _uid
属性。
在您的组件中像这样使用它:
<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" />
uuid
是一个不幸的名称选择,因此我将其重命名为 uidCounter
。 Javascript 是单线程的,所以我看不出上面的代码中可能会出现哪些竞争条件。 uidCounter
以原子方式读取和更新,因为没有其他线程并且执行不会被抢占。 Imo,对于这个用例,一个实际的 UUID 并没有比一个简单的递增计数器提供任何好处,但是它确实有效。
npm i -S lodash.uniqueid
然后在你的代码中......
<script>
const uniqueId = require('lodash.uniqueid')
export default {
data () {
return {
id: ''
}
},
mounted () {
this.id = uniqueId()
}
}
</script>
这样您就不会加载整个 lodash 库,甚至不会将整个库保存到 node_modules
。
id
属性。此外,自 2017 年以来,-S
(或 --save
)一直是 npm
的默认设置,实际上不再执行任何操作。
这似乎对我在 nuxtjs 中使用有用
https://www.npmjs.com/package/uuid
生成的输出示例:元素:47bfe557-d75f-455c-9a37-85b7935b297b
包.json
"dependencies": {
"uuid": "^8.3.2"
},
在子组件上,可能不是最好的方法,但似乎有效
...
<ComponentName v-if="element" />
...
import { v4 as uuidv4 } from 'uuid';
...
data() {
return {
element: null,
}
}
...
mounted() {
this.element = uuidv4();
}
我发现最简单的方法是通过全局 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>
如果你使用 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>
class
的语法的等价物是什么?例如使用 `export default defineComponent({ created() { ... }, ... });
我在回复中没有看到的一个简单方法是:
<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>
在 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
。
对于 DOM 中跨多个组件的非唯一 ID 的潜在问题,这个包似乎是一个很好的解决方案:
使用组件是一种趋势。组件很酷,它们很小、很明显、易于使用和模块化。直到涉及到 id 属性。一些 HTML 标签属性需要使用 id 属性,如 label[for]、input[form] 和许多 aria-* 属性。 id 的问题在于它不是模块化的。如果页面上的多个 id 属性具有相同的值,它们会相互影响。 VueUniqIds 可以帮助你摆脱这个问题。它提供了一组与 id 相关的指令,通过添加唯一字符串自动修改其值,同时保持属性易于阅读。
使用 https://www.npmjs.com/package/uuid 这似乎对我有用
生成的输出示例:元素:47bfe557-d75f-455c-9a37-85b7935b297b
包.json
"dependencies": {
"uuid": "^8.3.2"
},
组件.vue
v-if="element"
...
import { v4 as uuidv4 } from 'uuid';
...
data() {
return {
element: null,
}
}
...
mounted() {
this.element = uuidv4();
}
对于 Vue.js v3,您可以像这样获取 id:
在模板中:{{ $.uid }}
在脚本中:this.$.uid
或者使用你自己的函数或者混合它们:
this.componentUid = ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
);
这将返回例如:
aa174375-5b75-4919-acd0-980fcd54003c
如果您的 uid 未被其他组件使用,我有一个想法。
uid: Math.random()
简单而足够。
它也可以使用这种模式(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>
希望能帮助到你
不定期副业成功案例分享
ready
方法。当ready
方法没有执行时,我很困惑。 stackoverflow.com/a/40209796/126751data
必须是返回对象的函数:vuejs.org/v2/guide/components.html#data-Must-Be-a-Functionthis._uid
无效。相反,请自己生成您的 id,例如public id = uuid4();
,请参阅 uuid4。_uid
,它是“is reserved for internal use and it's important to keep it private (and not rely on it in user code) so that we keep the flexibility to change its behavior for potential future use cases”。