Vue2.5仿去哪儿app 实战项目笔记
swiper的自动构建 发送ajax请求 父子组件传值 兄弟组件间数据传递
swiper的自动构建
在首页的icon页面下,默认一个页面中包括8个图标。而我们希望若当页面中有9个图标时,可以左右拖动,形成轮播图的效果。而且我们希望页面能够自动计算和适配图标与轮播图,当图标数目变化时,轮播图也跟着相应变化。
所以应该设定两个v-for指令。分别遍历页面与图标。
<swiper-slide v-for="(page,index) of pages" :key="index">
<div class="icon" v-for="item of page" :key="item.id">
<div class="icons">
<swiper>
<swiper-slide v-for="(page,index) of pages" :key="index">
<!--包括两个v-for指令,第一个是根据页面数,在pages中遍历每一个轮播图页面。-->
<div class="icon"
v-for="item of page"
:key="item.id">
<!--第二个是在一个页面(page)内遍历8个图标-->
<div class="icon-img">
<img class="icon-img-content" :src='item.imgUrl' alt="">
</div>
<p class="icon-text"></p>
</div>
</swiper-slide>
</swiper>
</div>
利用计算属性,来实现根据图标数目自动构建页码,实现多页切换的轮播图效果。
computed: {
pages () {
const pages = []
this.iconList.forEach((item, index) => {
const page = Math.floor(index / 8)//向下取整
// 计算当前index所处页面page,一个页面包括8个icons
if (!pages[page]) {
pages[page] = []
// 当前page溢出,新建页面
}
pages[page].push(item)
})
return pages
// 根据数据自动构建页码,实现多页切换的轮播图
}
}
使用axios发送ajax请求
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端
对于home页面来说,每一个组件都有自己的数据,但为避免多次请求降低性能,所以希望整个首页只发送一个ajax请求,并且在home.vue
发送一个ajax请求在获取数据之后,能分别把数据传给每一个子组件。
//home.vue
methods: {
getHomeInfo () {
axios.get('/api/index.json').then(this.getHomeInfoSucc)
//这里的get路径为'/api/index.json'
//但本地的模拟数据在'/static/mock'目录下,需要借助路径代理
},
getHomeInfoSucc (res) {
res = res.data
//获取数据
if (res.ret && res.data) {
//后端正确返回结果
const data = res.data
this.city = data.city
this.swiperList = data.swiperList
this.iconList = data.iconList
this.recommendList = data.recommendList
this.weekendList = data.weekendList
//传递数据
}
}
},
mounted () {
this.getHomeInfo()
//借助mounted生命周期函数,让页面挂载好之后执行该函数
}
因为只有在/static
目录下的内容可以被外部访问到,所以将本地模拟数据放在./static/mock
目录下,并且在配置项中添加代理路径
//index.js
proxyTable: {
'/api': {
target: 'http://localhost:8080',
pathRewrite: {
'^/api': '/static/mock'
}
}
},
父子组件间传值
在父组件中,声明引入子组件,并传入子组件内需要的值
//home.vue
data () {
//初始化数据
return {
city: '',
swiperList: [],
iconList: [],
recommendList: [],
weekendList: []
}
},
子组件接收数据,注册props
//component.vue
props: {
recommendList: Array
//或 city: String
}
在主页面绑定每个组件
<!--home.vue-->
<!--父组件用属性的方式向子组件传值-->
<div class="">
<home-header :city="city"></home-header>
<home-swiper :list='swiperList'></home-swiper>
<!--把父组件获取到的数据赋给子组件-->
<home-icons :iconList='iconList'></home-icons>
<home-recommend :recommendList='recommendList'></home-recommend>
<home-weekend :weekendList='weekendList'></home-weekend>
</div>
swiper轮播图默认显示最后一张图片问题
当使用axios发送ajax请求后,会发现当页面加载完成后,轮播图默认会显示最后一张图片
这是因为页面还没有获取ajax数据时,props的list接收的是外部空数组,即最初创建时是通过空数组创建,获取完成ajax后,获取真正的数据,才重新渲染新数据。
解决方法:
让swiper的初次创建由完整的数据创建,而不使用空数组创建。
即当List为空数组时,不显示轮播图。
<swiper :options="swiperOption" v-if="showSwiper">
...
</swiper>
computed: {
showSwiper () {
return this.list.length
//也可直接使用v-if="list.length"
//但尽量不在模板内添加逻辑性的代码,所以添加一个计算属性来判断数据
}
}
兄弟组件间数据传递
实现右侧字母列表与城市列表同步
要实现当点击某个字母时,页面自动跳转到该字母对应的城市列表,需实现Alphabet.vue
与list.vue
这两个兄弟组件间的数据传递。
对于非父子组件传值,可借助父组件进行间接传递,即先将Alphabet.vue
传给city.vue
,city.vue
再转发给list.vue
Alphabet.vue传给city.vue(子组件向父组件传值)
//Alphabet.vue
handleClick (e) {
this.$emit('change', e.target.innerText)
//为字母绑定一个click事件,当点击时向外触发事件,事件的名字为‘change’,携带的内容即为这个字母
}
向外触发事件后,父组件city.vue
监听这个事件
<cityAlphabet :cities="cities" @change="handleClick"></cityAlphabet>
handleClick (letter) {
this.letter = letter
//接收Alphabet.vue传递过来的letter
}
city.vue将接收到的letter转发给list.vue(父组件向子组件传值)
<!--city.vue-->
<list :cities="cities" :hotCities="hotCities" :letter="letter"></list>
在list.vue中,借助监听器watch来监听letter的变化,并使页面随letter的改变而改变
<div class="area" v-for="(item,key) of cities" :key="key" :ref="key">
watch: {
letter () {
if (this.letter) {
// const element = this.$refs[this.letter]
// 此时element是一个数组,而不是一个DOM元素
const element = this.$refs[this.letter][0]
this.scroll.scrollToElement(element)
//让滚动区自动滚动到element对应的DOM元素上
}
}
}
其中
ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例.
而$refs是一个对象,即持有注册过ref特性的所有DOM元素和组件实例。