Vue中关于响应式的一个问题
最近在参加一个面试,对方发了一套面试题过来;要求是做一个类似京东生鲜的网站,要求实现商品列表功能;之前我一直都是在vue-cli脚手架中使用vue;由于这个页面比较少,所以直接引入的CDN但是却发现不能进行v-for渲染了。下面是我的错误代码
<!DOCTYPE html>
<html>
<body>
<div id="link-tab" >
<div class="tab-list" v-for="item in goodsdata">
<a class="goods-show">
<div class="goods-pic">
<img v-bind:src="item.imgurl" alt="fruit-picture"/>
</div>
<div class="goods-info">
<div class="goods-title">{{item.title}}</div>
<div class="goods-price">
<div class="price">
<span>¥{{item.price}}</span>
</div>
<div class="sale-price">
<span>¥{{item.salePrice}}</span>
</div>
</div>
<div class="goods-evalution">
<span class="evalute-num">{{item.evaluteNum}}条评价</span>
<span class="good-precent">好评{{item.goodsPrecent}}</span>
</div>
</div>
</a>
</div>
</div>
</div>
<script type="application/javascript" src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="application/javascript" src="http://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script type="application/javascript">
document.addEventListener("DOMContentLoaded", getTabList);
var _this = this;
var tab = new Vue({
el:'#link-tab',
data:{
goodsdata:[]
}
});
function getTabList() {
$.ajax({
type:"get",
url:"http://localhost:3000",
async:true,
success:function(res){
res = JSON.parse(res);
console.log(res.code);
if(res.code == 1){
_this.goodsdata = res.data ;
console.log(_this.goodsdata);
}else{
console.log("request ERROR");
}
}
});
}
</script>
</body>
</html>
页面一直没有渲染出结果,我的goodsdata里面是有数据的。如图:
我的流程是在页面加载的时候发送ajax请求获取数据;填充tablist,数据虽然获取到了,但是页面一直没有被填充。到这里我首先开始寻找原因,我想是不是我的Ajax请求发送的时候有问题;因为Ajax请求需要时间来进行请求和响应。而我监听的是DOM加载完毕之后触发Ajax请求拿数据。这样有可能导致的问题是我的界面中所有的DOM节点加载完毕,DOM树构建完成;而我初始化的goodsdata数据为空,后面的ajax请求拿到的数据是在DOM构建完成之后才拿到的;所以DOM树在第一次构建的时候不会渲染v-for所在的元素,因为里面的数据为空。
既然这样的话,那我是否可以在页面的DOM树加载之前就触发Ajax请求;这样就可以在DOM树构建之前拿到数据从而确保Vue能够进行正确的渲染。关于页面生命周期的介绍https://www.jianshu.com/p/3b581af02ebf 后来我了解到readystatechange事件,我想通过在loading地方做判断来执行ajax请求;但是似乎页面的readystatechage事件触发的时候,readyState属性的值就已经改变为interactive ;因此这条路似乎走不通。而根据我查询到的事件触发的顺序来说DOMContentLoaded事件的触发已经算得上是最开始的事件了,而且由于ajax请求是异步请求;在等待响应期间DOM会继续解析和渲染。因此等待在DOM进行渲染之前加载Ajax请求似乎可行性不大。
既然这条路走不通,那我就想到Vue的响应式。即数据发生改变时会动态的渲染DOM,于是我将代码进行了如下修改
var _this = this;
var goods= {goodsdata:[]};
document.addEventListener('DOMContentLoaded',getInfo());
var tab = new Vue({
el:'#link-tab',
data:_this.goods,
})
function getInfo(){
$.ajax({
type:"get",
url:"http://localhost:3000",
async:true,
success:function(res){
res = JSON.parse(res);//将JSON字符串序列化为JSON对象
if(res.code == 1){
_this.goods.goodsdata = res.data;
console.log(_this.goods.goodsdata);
}
else{
console.log("request ERROR")
}
}
});
}
我将this的指向提前声明给_this,然后创建了一个和Vue实例中data对象相同的对象goods;并将其加入到了data对象中;于是效果出现了。需要说明的只有data中的对象才会被响应。
而在Vue.js文档中是这么说的:当一个 Vue 实例被创建时,它向 Vue 的响应式系统中加入了其 data
对象中能找到的所有的属性。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值
原因是因为goods对象被加入到了Vue实例的data对象中,我改变了goods对象的值;由于Vue响应式的特点,这个值的改变被进行了追踪。所以DOM重新进行了渲染,
经过尝试我还发现下面这种方法也可以实现如上的效果:究其原因是因为我在created钩子函数部分执行了ajax请求,改变了data对象中goodsdata的值。所以Vue追踪到这个变化响应式的重新进行了渲染
var tab = new Vue({
el:'#link-tab',
data:{
goodsdata:[]
},
created:function({
var _this = this;
$.ajax({
type:"get",
url:"http://localhost:3000",
async:true,
success:function(res){
res = JSON.parse(res);
if(res.code == 1){
_this.goodsdata = res.data ;
console.log(_this.goodsdata);
}else{
console.log("request ERROR");
}
}
});
})
});
至此这个问题总算是解决了,但是关于为何只有data中的对象是被响应的;响应式的原理又是什么,我将在下面几篇文章中继续深入的去探究这个问题
以上是 Vue中关于响应式的一个问题 的全部内容, 来源链接: utcz.com/z/378084.html