博客已搬运至掘金,欢迎访问!
主页https://juejin.cn/user/2524134429703063
问题描述
Ant Design Vue Breadcrumb面包屑.,采用和 vue-router 进行结合使用的方法。
组件中routes和实例数据单向绑定(v-bind),通过更新routes来更新breadcrumb。
实际操作中在更新了routes之后,实例数据更新了,但breadcrumb并没有更新,
检查之后发现应该是因为绑定的数据对象是多层的结构,而数据更新发生在其中的某一部分,所以没有重新渲染
<template>
<div class="index">
<section>
<div id="content">
<a-breadcrumb class="contentBreadcrumb" :routes="routes">
<template slot="itemRender" slot-scope="{ route, routes, paths }">
<span v-if="routes.indexOf(route) === routes.length - 1">
{{ route.breadcrumbName }}
</span>
<router-link v-else :to="`${basePath}/${paths.join('/')}`">
{{ route.breadcrumbName }}
</router-link>
</template>
</a-breadcrumb>
<h1>obj: {{ obj }}</h1>
<h1>arr: {{ arr }}</h1>
<nav>
<router-link
to=""
@click.native="
render_breadcrumb({
path: `A`,
breadcrumbName: `信息A`,
})
"
>
<div class="tab_label">
<span> 信息A</span>
</div>
</router-link>
<router-link
to=""
@click.native="
render_breadcrumb({
path: `B`,
breadcrumbName: `信息B`,
})
"
>
<div class="tab_label">
<span> 信息B</span>
</div>
</router-link>
<router-link
to=""
@click.native="
render_breadcrumb({
path: `C`,
breadcrumbName: `信息C`,
})
"
>
<div class="tab_label">
<span> 信息C</span>
</div>
</router-link>
</nav>
</div>
</section>
</div>
</template>
<script>
export default {
name: "Index",
components: {},
props: {
// msg: String,
},
data() {
return {
msg: "Welcome to Your Vue.js App",
basePath: "",
routes: [
{
path: "",
breadcrumbName: "首页",
},
{
path: "",
breadcrumbName: "信息公开",
},
{
path: "",
breadcrumbName: "最新信息",
},
],
arr: [{ ax: 1 }, { ay: 2 }, { az: 3 }],
obj: { ox: 1, oy: 2, oz: 3 },
};
},
watch: {
routes(val, preVal) {
console.log("routes change");
},
obj(val, preVal) {
console.log("obj change");
},
arr(val, preVal) {
console.log("arr change");
},
},
methods: {
render_breadcrumb(breadcrumb_item) {
this.routes[this.routes.length - 1] = {
path: "",
breadcrumbName: `${breadcrumb_item.breadcrumbName}`,
};
console.log(this.routes);
// this.routes = [
// {
// path: "",
// breadcrumbName: "首页",
// },
// {
// path: "",
// breadcrumbName: "信息公开",
// },
// {
// path: "",
// breadcrumbName: `${breadcrumb_item.breadcrumbName}`,
// },
// ];
// console.log(this.routes);
// this.obj[this.obj.length - 1] = {
// path: "",
// breadcrumbName: `${breadcrumb_item.breadcrumbName}`,
// };
// console.log(this.obj);
// this.obj = [
// { ox: 1 },
// { oy: 2 },
// { oz: `${breadcrumb_item.breadcrumbName}` },
// ];
// console.log(this.obj);
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
#content {
margin: auto;
width: 65%;
padding: 50px 0;
}
.contentBreadcrumb {
font-size: 1rem;
font-weight: 500;
margin: 0 0 15px 0;
}
nav {
margin: 50px 0;
}
nav .tab_label {
width: 15%;
margin: 15px 0;
padding: 15px 25px;
background-color: #409eff;
color: #fff;
font-weight: 700;
text-align: center;
border-radius: 1px;
}
</style>
问题原因和分析
原因
实例中定义的数据是一个多层的对象,如果通过对象内部的方法去更新部分数据,数据更新了,Vue实例可能无法监测到数据的变化,所以不会重新渲染(不知道这样表达准不准确)
分析
-
如果像这部分代码一样只更新部分数据,数据更新了,但breadcrumb并没有更新
通过控制台打印的数据可知,数据更新了,但侦听器并没有监测到数据的变化
render_breadcrumb(breadcrumb_item) {
this.routes[this.routes.length - 1] = {
path: "",
breadcrumbName: `${breadcrumb_item.breadcrumbName}`,
};
console.log(this.routes);
},
- 将全部数据重新赋值,数据更新了,breadcrumb更新了
通过控制台打印的数据可知,数据更新了,侦听器监测到了数据的变化
render_breadcrumb(breadcrumb_item) {
// this.routes[this.routes.length - 1] = {
// path: "",
// breadcrumbName: `${breadcrumb_item.breadcrumbName}`,
// };
// console.log(this.routes);
this.routes = [
{
path: "",
breadcrumbName: "首页",
},
{
path: "",
breadcrumbName: "信息公开",
},
{
path: "",
breadcrumbName: `${breadcrumb_item.breadcrumbName}`,
},
];
console.log(this.routes);
},
猜想
为什么Vue实例侦听器并没有监测到数据的变化,没有重新渲染数据?
可能是因为如果通过实例数据去访问更新对象的部分数据,改变的是对象本身的数据,而实例数据和对象之间的引用关系并没有发生变化,所以侦听器并没有监测到数据的变化
通过给实例数据重新,实例数据和原来的对象之间的引用关系发生了变化,实例数据引用了新的对象,侦听器监测到数据的变化,重新渲染数据
解决方法
- 给实例数据重新赋值
- 通过Vue计算属性(computed)和侦听器(watch).