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中的对象是被响应的;响应式的原理又是什么,我将在下面几篇文章中继续深入的去探究这个问题

猜你喜欢

转载自blog.csdn.net/shengbeer/article/details/87739635