BScroll回顾: 外层有一个容器,定义了视口的高度,内层div可以被内容自动撑高,当内层容器高度超过视口高度时,就会出现滚动
1)接收传递进来的seller数据,并编写界面和样式
props: {
//APP.vue的routerview中已经将seller传进来了,这里只需要接收就好
seller: {
type: Object
}
},
<div class="overview">
<h1 class="title">{{seller.name}}</h1>
<div class="desc border-1px">
<star :size="36" :score="seller.score"></star>
<span class="text">({{seller.ratingCount}})</span>
<span class="text">月售{{seller.sellCount}}单</span>
</div>
<ul class="remark">
<li class="block">
<h2>起送价</h2>
<div class="content">
<span class="stress">{{seller.minPrice}}</span>元
</div>
</li>
<li class="block">
<h2>商家配送</h2>
<div class="content">
<span class="stress">{{seller.deliveryPrice}}</span>元
</div>
</li>
<li class="block">
<h2>平均配送时间</h2>
<div class="content">
<span class="stress">{{seller.deliveryTime}}</span>元
</div>
</li>
</ul>
<div class="favorite" @click="toggleFavorite($event)">
<i class="icon-favorite" :class="{'active':favorite}"></i> <!-- 对应是否收藏两种样式-->
<span>{{favoriteText}}</span> <!-- 有没有选中对应不同的文本,所以这里要绑定一个变量,放到data中 -->
</div>
</div>
2)添加公告与活动部分,先添加一个split组件,在添加内容,不要忘了把图片拷贝过来
<div class="bulletin">
<h1 class="title">公告与活动</h1>
<div class="content-wrapper border-1px">
<p class="content">{{seller.bulletin}}</p>
</div>
<ul v-if="seller.supports" class="supports">
<li class="support-item border-1px" v-for="(item,index) in seller.supports" :key="(item.id,index.id)">
<span class="icon" :class="classMap[seller.supports[index].type]"></span>
<span class="text">{{seller.supports[index].description}}</span>
</li>
</ul>
</div>
<split></split>
3)页面过长,将BScroll引入进来
3.1 .初始化BScroll语句放在created(),按照DOM的生命周期来说,执行到DOM的时候不能保证DOM已经被渲染了,在goods.vue中把BScroll初始化语句写在created()中,是因为前半部分先执行了获取api数据的语句,在seller中,数据是通过props传进来的,不能保证数据是否已经被渲染了
3.2 初始化BScroll语句放在ready中又不起作用,DOM被渲染完之后,ready是自动被执行的,在ready中写的代码都可以安全的去使用DOM,但是高度计算不对,无法正确滚动,原因:seller是异步获取的,但是我们的内容都是靠seller里的数据撑开的,,所以一开始内容肯定是小于我我们定义的wrapper的,所以没有被撑开
3.3 将其放入watch:{}中可以watch到seller的变化,将初始化语句写成一个方法,在watch中进行调用
watch: {
'seller'() {
this._initScroll();
this._initPics();
}
},
_initScroll() {
if (!this.scroll) {
this.$nextTick(() => {
this.scroll = new BScroll(this.$refs.seller, {click: true});
});
} else {
this.scroll.refresh();
}
},
_initPics() {
if(this.seller.pics) {
let picWidth = 120;
let margin = 6;
let width = (picWidth + margin) * this.seller.pics.length - margin;
this.$refs.picList.style.width = width + 'px'; //不要忘记加单位
if(!this.picScroll){
this.$nextTick(() => {
this.picScroll = new BScroll(this.$refs.picWrapper, {
scrollX: true, //表示横向滚动
eventPassthrough: 'vertical' //横向滚动图片的时候就忽略垂直方向的滚动
});
});
} else {
this.picScroll.refresh();
}
}
}
3.4 .每次切换商家页面时,DOM被重新渲染,又不能滚动了,因为在watch中只能观测到seller的变化,切换区块的时候seller没有变化,所以seller中的watch不会被执行,所以BScroll就不会初始化。我们在ready方法中重新加入初始化语句
watch: {
'seller'() {
this._initScroll();
this._initPics();
}
},
ready() {
this._initScroll();
this._initPics();
//设定ul的宽度
},
一定要为初始化函数_initScroll()和this._initPics()中的nextTick()下的添加if-else语句,因为ready的执行时机要先于watch中的seller,然后我们在执行seller中的initScroll的时候就会发现BScroll已经被初始化了,所以initScroll失效,即使在watch中观察到变化也只能什么都不做,所以我们将一个else选项,对BScroll进行刷新,完成
6.添加图片,设置样式,横向排列并实现横向滚动,ul是外层的宽度,并不是真实的li撑开的宽度,使用BScroll实现滚动,添加—_initPic()方法,并把它添加到watch和ready中
<div class="pics">
<h1 class="title">商家实景</h1>
<div class="pic-wrapper" ref="picWrapper">
<ul class="pic-list" ref="picList">
<li class="pic-item" v-for="pic in seller.pics" :key="pic.id">
<img :src="pic" width="120" height="90">
</li>
</ul>
</div>
</div>
<split></split>
.pics
padding 18px
.title
margin-bottom 12px
line-height 14px
color rgb(7, 17, 27)
font-size 14px
.pic-wrapper
width 100%
overflow hidden
white-space nowrap /*不产生折行*/
.pic-list
font-size 0
.pic-item
display inline-block
margin-right 6px
width 120px
height 90px
&:last-child
margin 0
7.添加收藏按钮,设置:active样式(红,白)和字体的变化(收藏和未收藏)
<div class="favorite" @click="toggleFavorite($event)">
<i class="icon-favorite" :class="{'active':favorite}"></i> <!-- 对应是否收藏两种样式-->
<span>{{favoriteText}}</span> <!-- 有没有选中对应不同的文本,所以这里要绑定一个变量,放到data中 -->
</div>
data() {
return {
// favorite: false, //默认没有被收藏,从localStorge中取读取,不是一个默认值了
favorite: (() => {
return loadFromlLocal(this.seller.id, 'favorite', false);
})()
};
},
computed: {
favoriteText() {
return this.favorite ? '已收藏' : '收藏';
}
},
methods中
toggleFavorite(event) {
if (!event._constructed) {
return;
}
this.favorite = !this.favorite;
//这样写取法区分商家id,不同商家的状态一样
//localStorage.favorite = this.favorite;
saveToLocal(this.seller.id, 'favorite', this.favorite);
},
刷新之后,收藏样式就会消失,将收藏的信息添加到localStorge中,创建store.js实现数据的存取
//savaToLocal(this.seller.id, 'favorite', this.favorite);
export function saveToLocal(id, key, value) { //存储到localStorge
let seller = window.localStorage.__seller__;
if (!seller) { //没有seller的时候,初始化,定义一个seller对象,并给他设定一个id
seller = {};
seller[id] = {};
} else {
seller = JSON.parse(seller); // JSON 字符串转换为对象
if (!seller[id]) { //判断是否有当前这个商家
seller[id] = {};
}
}
seller[id][key] = value;
//将一个JavaScript值(对象或者数组)转换为一个 JSON字符串
window.localStorage.__seller__ = JSON.stringify(seller);
}
//loadFromlLocal(this.seller.id, 'favorite', false);
export function loadFromlLocal(id, key, def) { //读取,读不到的时候传入一个default变量
let seller = window.localStorage.__seller__;
if (!seller) {
return def;
}
seller = JSON.parse(seller)[id];
if (!seller) {
return def;
}
let ret = seller[key];
return ret || def;
}
引入:
import {saveToLocal, loadFromlLocal} from 'common/js/store.js';