Vue常见问题汇总
Vue2
这篇文章是我在工作中使用 vue 遇到的问题做的简单汇总,希望能对看到这篇文章的你有所帮助
对象数组 响应式所引发的问题
对于对象
Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter (defineProperty)转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的
解决
vm.$set(obj,"key",value)
// 或者
vm.obj = {...vm.obj,key:value}
// 或者
vm.obj = Object.assgin({},vm.obj,{key:value})
对于数组
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
Vue 不能检测以下数组的变动:
当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength
解决
修改数组某一项
vm.$set(vm.items, indexOfItem, newValue)
// 或者
vm.items.splice(indexOfItem, 1, newValue)
修改数组长度
vm.items.splice(newLength)
// 或者
vm.items = vm.items.slice(0,newLength)
vue 中给数组中的对象,添加新属性属性
不能使用直接遍历设置的方法
this.items.forEach((item) => {
item.key = value;
});
解决
this.items.forEach((item, index) => {
this.$set(this.items, index, { ...item, ...{ key:value } });
//或者
this.items.splice(index, 1, { ...item, ...{ key:value } });
});
// 或者
this.items = this.items.map( item =>{
return { ...item, ...{ key:value } }
})
tip 修改数组中的属性 直接修改即可 数组中的对象同外层对象的响应方式
v-if 使用时注意 vue 会将一样的元素复用 需要加 key 解决
在下面的案例中 即使渲染出返回按钮 因为下面的每个 else 元素都一样 但是返回依然不现实 因为复用了下面的元素样式 display: none; 需要在不需要复用的元素上加 key 解决
<div class="top-button" v-if="isView">
<el-button type="primary" plain @click="isView = false" icon="iconfont iconfont-hcm-back">返回</el-button>
</div>
<div class="top-button" v-else-if="isEdit === false">
<el-button type="primary" plain @click="onNewPayment" icon="iconfont iconfont-hcm-add" v-btn:edit="$route.query"
>新建</el-button
>
<el-button
type="primary"
icon="iconfont iconfont-xinchou-fabu"
plain
@click="onPublish(true)"
v-btn:edit="$route.query"
>发布</el-button
>
<el-button
type="primary"
icon="iconfont iconfont-xinchou-quxiaofabu"
plain
@click="onPublish(false)"
v-btn:edit="$route.query"
>取消发布</el-button
>
<el-button type="primary" plain @click="onClickCancelPublish" v-btn:edit="$route.query">设置启动时间</el-button>
<el-button
type="primary"
plain
@click="$refs.changeLogDialog.open(currentNode.data.id, false)"
v-btn:view="$route.query"
>查看变更记录</el-button
>
</div>
<div class="top-button" v-else-if="isEdit">
<el-button type="primary" plain @click="onEditSave" icon="iconfont iconfont-hcm-save">保存</el-button>
<el-button type="primary" plain @click="onEditCancel" icon="iconfont iconfont-hcm-delete">取消</el-button>
</div>
</el-header>
vue 样式:scoped 使用
深度作用选择器
如果你希望 scoped
样式中的一个选择器能够作用得“更深”,例如影响子组件,你可以使用 >>>
操作符:
<style scoped>
.a >>> .b {
/* ... */
}
</style>
上述代码将会编译成:
.a[data-v-f3f3eg9] .b {
/* ... */
}
注意点
注意点:如果子组件dom不在父组件内部 例如:dialog组件, 通过深度作用选择器也不会生效
这时需要通过 全局样式即去除 scoped + 子组件calss + 选择器 来实现
有些像 Sass 之类的预处理器无法正确解析 >>>
。这种情况下你可以使用 /deep/
或 ::v-deep
操作符取而代之——两者都是 >>>
的别名,同样可以正常工作。
Vue 中的 v-bind 使用问题
在 vue 中使用 v-bind 绑定对象时 需要注意 :v-bind 绑定值不会覆盖之前的属性
<input
type="text"
class="test"
:disabled="false"
v-bind="{ disabled: true, class: 'test3' }"
/>
<!-- 上面的代码disabled显示的还是false 但是class可以进行合并 显示:class="test test3" -->
<input
type="text"
class="test"
:class="'test2'"
:disabled="false"
v-bind="{ disabled: true, class: 'test3' }"
/>
<!--注意: class 只能合并一次 最后显示 class="test test2"-->
模板 v-bind 绑定值的变量名为 class 报 'v-bind' directives require an attribute value.eslint
在模板中绑定的名称不要用 class 作为命名 否则 eslint 会报'v-bind' directives require an attribute value.eslint
$attrs 可以获取任何绑定在组件上的属性 但(
porp
中的属性和class
和style
除外)
vue-property-decorator 注意事项(ts 项目中)
介绍链接[https://segmentfault.com/a/1190000019906321]
1.新建组件必须加@Component 否则组件会怎样都不现实
router 传参 注意事项
路由传参 query 和 params 显示到地址栏形式的 注意 不要超长 ,否则浏览器会报 413 错误 , 传参需要按需传送
prop 中默认值返回空对象
prop 中 default 默认值 返回对象或数组需要使用工厂函数 ,一般我们都会用箭头函数简写
props: {
defaultText: {
type: Array,
default: ()=> [] // 工厂函数返回空数组
},
// 错误写法
defaultAttrs: {
type: Object,
default: ()=> {} // 但是返回空对象就不能直接=>{} 这样就代表函数的块级作用域了 会报错
},
// 正确写法
defaultAttrs: {
type: Object,
default: ()=> ({}) // 在{}外面包一层()即可
},
},
使用 v-on="$listeners" 的注意事项
问题
内部使用了 v-on="$listeners" 的组件事件被重复调用
案例
这里有个 Father 组件
<Child v-on="$listeners" @click="$emit('click')" />
Child组件上用$listeners接收外部传入的所有事件 同时有独立 click 绑定
<Father @click="onClick" ></Father>
Father 组件上 绑定 onClick
行为
此时触发 Child组件的 click 事件
结果
onClick事件被触发 2 次
原因
$listeners 中 click 和 单独绑定的 click 都被掉用了
我们在 Father 的 created中看一下 $listeners
this.$listeners // { click: ƒ, input: ƒ}
过程
Father.\(listeners.click 直接被绑到了 Child 上 @click 也被绑定到到了 Child 上
Child click 被触发
1 调用 Father.\)listeners.click (也就是onClick)
2 调用 @click -> 触发 $emit('click') -> 调用 onClick
解决
v-on="$listeners" 同时又想自己绑定一些事件的情况 防止重复调用 可以使用合并事件的方式
<Child v-on="listeners" />
export default {
name: "Father",
components: {
Child,
},
computed: {
listeners() {
return {
...this.$listeners,
// 用下面 click 覆盖 this.$listeners.click
click: () => this.$emit("click"),
};
},
},
};
注意点 $attrs 不会出现这种情况
$attrs 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)
意味着 prop中的属性 就不会出现在 $attrs 中 ,导致重复出现
Vue3 去除了$listeners
vue3 中去除了 $listeners 统一在 $attrs 中
并且 添加了 emits ,同 props 用法类似, 是用于定义需要触发的事件的
在 emits 和 props 定义的属性 都不会在 $attrs 中出现 ,这意味的不会出现多次调用的可能 ! vue3是挺好!
Vetur 在vue文件中 script 不高亮
在 vue 文件中不高量
原因
</template>
标签位置不对