去哪儿-06-home-ajax

目标: 使用Ajax动态获取首页的数据

准备阶段:

1. 创建分支index-ajax
2.  vue中发送ajax有很多工具, 比如 浏览器自带的fetch, vue-resource, axios,  我们选用axios
3.  安装axios: npm install axios --save
4.  如果发现,昨天写的代码并没有合并到主分支上,会发现今天访问的时候,昨天的内容都不见了, 是因为,今天的分支是从主分支上拉取过来的,所以就不会有昨天的代码。首先要先合并一下代码,在index-ajax分支下:`git merge index-recommend` 

需要思考的问题

1. 如何发送ajax请求? 已经写过5个子组件了,每一个组件都有自己的数据,需要每一组件都发送一个ajax请求吗?   首页的5个组件都发送ajax请求的话,首页就要发送5次请求,将会极大影响网站的性能。
2. 能否整个首页只发送一个ajax请求? 如果只发送一个,应该从哪里发送? 答: 由Home.vue来获取ajax数据,获取到之后,由它将数据分别传递给各个子组件。

首页发送ajax请求

  1. 引入 axios
  2. 借助生命周期函数的mounted, 让页面挂载好之后去执行getHomeInfo这个函数(函数定义在methods中)
export default {
    name: 'Home',
    components: {...此处省略子组件的名字},
    methods: {
        getHomeInfo () {
            axios.get('/api/index.json')
                 .then(this.getHomeInfoSucc)
        },
        getHomInfoSucc (res) {
            console.log(res)
        }
    },
    mounted () {
        this.getHomeInfo()
    }

}

注意: axios返回的结果是一个Promise对象,所以可以then, then里面是一个函数,不是函数的调用,表示在resolve的时候执行这个函数。页面一挂载完成,就去请求ajax数据,数据获取成功,就把数据打印出来。
3. 这个时候会报错,表示找不到这个json文件,在没有后端支持的情况下,如何实现数据的模拟?

  1. 在项目中有一个static目录,存放的是静态文件,创建一个名为mock的目录,在里面新建一个index.json文件。
  2. 将数据文件存放在这里的原因: 因为只有static目录下的文件才能被外部访问到。就类似于在NodeJS阶段开放的public资源目录。
  3. 如果不希望将这个本地的数据文件提交到线上,可以在文件夹下的.gitignore文件,在里面添加一项: static/mock ,表示在进行代码提交的时候不会被提交到本地或者线上仓库中。
  4. 此时要想访问这个json数据,路径就得改了:axios.get('/static/mock/index.json'), 但是我们使用的是本地模拟的接口地址,如果代码上线,写这样的地址是获取不到的, 就需要重新将地址格式修改成axios.get('/api/index.json')这种格式,但是在上线之前改动代码是有风险的,不建议这样做,如何解决? 思路: 是否有一个转发机制,能够帮助我们把对api下面所有的json文件的请求转发到本地的mock文件夹下?
  5. 上述问题的具体操作: vue中提供了一个proxy代理的功能,通过这个功能就可以解决上述问题。 打开config目录下的index.js文件在开发环境中,官方提供了一个proxyTable的一个配置项,进行如下配置:
 proxyTable: {
   '/api': {
     target: 'http://localhost:8081',
     pathRewrite: {
       '^/api': '/static/mock'
     }
   }
 }

实际上这个功能是由webpack-dev-server提供的。表示的是当用户请求路径/api开头的时候,它会定位到/static/mock对应的目录,就可以请求里面的json数据了。(记得修改配置项文件之后都需要重启服务器)

至此,就获取到了ajax数据。

首页父子组件的数据传递

  1. 在Home中创建一个data数据函数,存储需要的数据。

  2. 首先, data函数返回的数据对象中有一个city,将这个city传给子组件home-header,使用属性的形式进行传递,即: <home-header :city="city"></home-header>, 然后在子组件Header.vue中接收这个数据,并渲染到页面,即使用props来接收这个来自父组件的数据:
    Home.vue中:

     data () {
             return {
                 city: ''
             }
         }
    

    子组件Header.vue中:

     export default {
         name: 'HomeHeader',
         props: {
             city: String
         }
     }
    

    使用插值表达式的形式将city数据渲染到页面中 “城市”的位置:

    <div class="header-right">
         {{this.city}}
         <span class="iconfont arrow-icon">&#xe843;</span>
     </div>
    
  3. 从利用ajax获取到的数据中提取出我们需要的city:

    getHomeInfoSucc (res) {
        res = res.data
        if (res.ret && res.data) {
            // 表示如果后端正确返回了结果,并且res里面有data内容项,就是服务器返回的所有数据
            const data = res.data
            this.city = data.city
        }
        
    }
    

    此时,this.city就是从json数据中获取到的具体城市,这个city的值通过属性<home-header :city="city"></home-header>传给子组件,子组件Header.vue中props接收这个数据,然后渲染到{{this.city}}的位置,数据库中city发生变化,子组件中对应位置上就会发生同样的动态变化。

  4. swiperList的获取
    Home.vue中:

     data () {
             return {
                 city: '',
                 swiperList: []
             }
         }
    

    传给组件: <home-swiper :swiperList="swiperList"></home-swiper>
    子组件Swiper.vue中接收数据, 原本的swiperList数据就可以直接删除,取而代之的是使用一个props接收来自父组件的swiperList数据。

     export default { 
     name: 'HomeSwiper',
     props: {
         list: Array
     },
     data () {
       return {
         swiperOption: {
           pagination: '.swiper-pagination',
           loop: true
         },
         // swiperList: [{
         //     id: '0001',
         //     imgUrl: 'http://img1.qunarzz.com/sight/source/1505/7d/df6ff468331c43.jpg_r_640x214_1f3783d0.jpg'
         // },{
         //     id: '0002',
         //     imgUrl: 'http://img1.qunarzz.com/sight/source/1505/24/f947f286f2cf61.jpg_r_640x214_46fb6378.jpg'
         // },{
         //     id: '0003',
         //     imgUrl: 'http://img1.qunarzz.com/sight/source/1505/aa/7baaf8a851d221.jpg_r_640x214_1431200f.jpg'
         // }]
       }
     }
     } 
    

    然后将这个数据渲染到页面中去。
    当ajax中数据修改的时候,就要在Home.vue中获取到:

    getHomeInfoSucc (res) {
        res = res.data
        if (res.ret && res.data) {
            // 表示如果后端正确返回了结果,并且res里面有data内容项,就是服务器返回的所有数据
            const data = res.data
            this.city = data.city
            this.swiperList = data.swiperList
        }
    }
    

    此时会发现, 轮播图的效果呈现出来了,但是在刚开始的时候,它默认是显示的最后一张图片,原因是一开始的swiperList: []它是一个空数组, 当数据发生变化的时候它获取到数据才会重新渲染到页面上去,要想默认显示的是第一张图片,可以加一个判断,判断这个数据不是空数组的时候渲染:

     <swiper :options="swiperOption" v-if="list.length">
        <swiper-slide v-for="item of list" :key="item.id">
            <img class="swiper-img" :src="item.imgUrl" />
        </swiper-slide>
        <div class="swiper-pagination"  slot="pagination"></div>
    </swiper> 
    

    代码美化: (在模板里面尽量避免出现这种逻辑性的代码) — 设置一个计算属性

    export default { 
        name: 'HomeSwiper',
        props: {
            list: Array
        },
        data () {
        return {
            swiperOption: {
            pagination: '.swiper-pagination',
            loop: true
            }
        }
        },
        computed: {
            showSwiper () {
                return this.list.length
            }
        }
    } 
    

    然后就可以之前写v-if="showSwiper"

  5. iconList数据的获取

  6. recommendList数据获取

  7. weekendList数据获取, 这几个数据的传递与接收、渲染的流程是一样的,不再重复。

一个小问题

icons图标区域会自动的来回滚动, 希望去除自动来回切换的效果: 将Swiper.vue中的:options="swiperOption"粘贴到Icons.vue的swiper标签中,然后在Icons.vue中设置swiperOption:

data () {
    return {
        swiperOption: {
            autoplay: false
        }
    }
}

代码提交

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值