Vue自定义指令中如何正确设置data变量?报错求助
问题原因分析
你碰到的这个错误核心原因很明确:自定义指令的钩子函数里的this并不指向你的Vue组件实例。在bind钩子中直接用this.bgcolor尝试修改组件的data变量时,this其实是undefined(严格模式下),自然就会抛出"Cannot set property 'bgcolor' of undefined"的错误。
另外还有一个逻辑问题:你现在用的是组件级的bgcolor变量,但你在v-for循环里渲染多个SceneCard,这样所有卡片都会共享同一个bgcolor值,最终只会显示最后一次生成的随机色,这显然不符合你"每个卡片随机色"的需求。
解决方案
下面给你两种可行的解决思路,你可以根据自己的习惯选择:
方案一:修正自定义指令,结合vnode访问组件实例并为每个scene单独存颜色
首先修改你的SceneList组件,给每个scene对象添加专属的背景色属性,然后通过指令的vnode参数拿到组件实例,修改对应scene的颜色:
<template> <div id="scene-list"> <!-- 现在绑定的是scene的bgColor属性 --> <scene-card class="scene-card-comp" v-for="scene in scenes" :key="scene.id" :bgcolor="scene.bgColor" v-rainbow="scene" > </scene-card> </div> </template> <script> import SceneCard from './SceneCard.vue'; export default { props: ['scenes'], components: { SceneCard }, directives: { rainbow: { bind(el, binding, vnode) { const bgColor = `#${Math.random().toString().slice(2, 8)}`; el.style.backgroundColor = bgColor; el.style.opacity = '0.5'; // 通过binding.value拿到传入的scene对象,直接给它添加bgColor属性 binding.value.bgColor = bgColor; } } } }; </script>
这样每个scene都会有自己的bgColor,传给对应的SceneCard后,子组件就能拿到正确的颜色值了。
方案二:去掉自定义指令,直接在循环时生成随机色(更简洁)
其实这个需求完全不需要自定义指令,直接在组件初始化时给每个scene添加随机色,或者在模板里动态生成:
方式1:在组件created钩子中初始化颜色(推荐,颜色不会随渲染重复生成)
<template> <div id="scene-list"> <scene-card class="scene-card-comp" v-for="scene in scenes" :key="scene.id" :bgcolor="scene.bgColor" :style="{ backgroundColor: scene.bgColor, opacity: 0.5 }" > </scene-card> </div> </template> <script> import SceneCard from './SceneCard.vue'; export default { props: ['scenes'], components: { SceneCard }, created() { // 给每个scene添加随机背景色 this.scenes.forEach(scene => { scene.bgColor = `#${Math.random().toString().slice(2, 8)}`; }); } }; </script>
方式2:直接在模板中动态生成(适合简单场景,组件重渲染会换颜色)
<template> <div id="scene-list"> <scene-card class="scene-card-comp" v-for="scene in scenes" :key="scene.id" :bgcolor="`#${Math.random().toString().slice(2, 8)}`" :style="{ backgroundColor: `#${Math.random().toString().slice(2, 8)}`, opacity: 0.5 }" > </scene-card> </div> </template> <script> import SceneCard from './SceneCard.vue'; export default { props: ['scenes'], components: { SceneCard } }; </script>
验证效果
修改完成后,点击SceneCard的changeBGColor方法时,控制台应该会打印出当前卡片对应的随机颜色代码,说明颜色已经正确传递给子组件了。
内容的提问来源于stack exchange,提问作者Humoyun Ahmad
相关产品推荐
相关产品推荐

