计算机里面没有黑魔法
common是公共的,可以在多个项目使用 content是和本项目业务有关的公共文件
我来一一介绍
项目优化
1,添加home.js作为中间件,专门管理home模块的所有网络请求
- home.vue面向home.js开发
- home.js面向request.js
这样做的好处是,可以使网络请求的代码和.vue文件里的函数分离开,防止耦合(良好的代码设计)
home页
函数里面的变量是局部变量,函数执行完,数据就不存在了(被内存回收掉),函数的调用带。
函数调用:是把变量压入函数栈,函数执行结束,变量会pop出来,被内存回收掉
垃圾回收
- 当函数执行完之后,变量被回收,变量指向对象的箭头(指针)消失了,然后对象因为没有指针指着他也会被回收
所以我们才需要另外创建一个变量,把res赋给它,然后由它来指向原来res指向的对象,这样对象(数据)就不会被回收
我们这样取,直接取到list(只是这个项目这样,而且是看了数据才这样决定的)
然后我们就取出来优美的一个个对象的格式
github上面有很多vue的UI库(ui小组件),可以拿下来直接用,就像轮播图这样的其实也是小组件
我们把**可以单独用的功能(代码)**取出,创建一个home子组件,把它放进home的子组件里
<swiper>
<swiper-item v-for="item in banners">
<a :href="item.link">
<img :src="item.image" alt="">
</a>
</swiper-item>
</swiper>
然后再在母组件里,导入子组件,并且把数据传给调用过来的子组件。。。如图
flex到底是啥意思
关于滚动问题,我们后面会用到一个叫better-scroll
position: fixed;
这是什么意思???
导入组件的时候,把公共组件,子组件,方法分隔开,养成良好的代码规范
import NavBar from "../../components/common/navbar/NavBar";
import TabControl from "../../components/content/tabControl/TabControl";
import HomeSwiper from "./childComps/HomeSwiper";
import RecommendView from "./childComps/RecommendView";
import FeatureView from "./childComps/FeatureView";
import {gethomemultidata} from "../../network/home";
吸顶效果:
- 监听滚动
简单法(不过如果要兼容ie就不要这样做)
.tab-control{
position: sticky;
top: 44px;
}
如何解决vue自带的复用问题,如果你不想让input复用的话,你可以绑定一个key
保存商品的数据结构设计
- 这里我们直接这样做
数据结构
- map类数据结构
怎么把一个数组的内容同步(塞)到另一个数组
push本身语法,括号里面表示可变参数,意思就是可以push很多
一旦你看到一个函数里面有很多...意味着可以传很多东西,这是一个语法,对数组进行解析,把元素一个一个push出来
goods:{
'pop':{page:0,list:[]},
'news':{page:0,list:[]},
'sell':{page:0,list:[]},
}
我们来看看一开始加一,为什么后面还要加呢?(没错,我们把方法封装了,在created里面只是引用了一下)
created() {
this.gethomemultidata()
this.getHomeGoods('pop')
},
methods:{
getHomeGoods(type){
const page =this.goods[type].page + 1
getHomeGoods(type,page).then(res => {
this.goods[type].list.push(...res.data.list)
this.goods[type].page+=1
})
}
因为我们这里定义的page变量是为了获得最新页码,然后传给后台服务器看,它的名字甚至可以不用叫page 如图 还有这种塞list的做法是动态的,相当于网址不一样时,又塞一次,所以我们刷新网页的时候会变化。
心累,看看下面两个属性作用
.goods{
display: flex;
flex-wrap: wrap;//包裹,防止挤一块
justify-content: space-around;//均等分(中间缝隙等于侧边的两倍)
}
如果不满意,可以微调,比如设置padding
父子件通信(我服了我又忘了)
props:{//从外面传进来
titles:{
type:Array,
default(){
return[]
}
}
itemClick(index){
this.currentIndex =index;
this.$emit('tabClick',index)//从里面传出去
}
case穿透???
为什么下面这里要加两个this,this到底是是什么??
computed:{
showGoods(){
return this.goods[this.currentType].list
}
},
移动端滚动卡顿怎么办
- github,iscroll(太老了不用它)
- better scroll (用它) npm install better scroll
- 然后,
<template>
<div class="wrapper" ref="aaa">
<ul>
<li>顺滑演示1</li>
<li>顺滑演示2</li>
<li>顺滑演示3</li>
<li>顺滑演示4</li>
<li>顺滑演示5</li>
<li>顺滑演示6</li>
<li>顺滑演示7</li>
<li>顺滑演示8</li>
<li>顺滑演示9</li>
<li>顺滑演示10</li>
<li>顺滑演示11</li>
<li>顺滑演示12</li>
<li>顺滑演示13</li>
<li>顺滑演示14</li>
<li>顺滑演示15</li>
<li>顺滑演示16</li>
<li>顺滑演示17</li>
<li>顺滑演示18</li>
<li>顺滑演示19</li>
<li>顺滑演示20</li>
<li>顺滑演示21</li>
<li>顺滑演示22</li>
<li>顺滑演示23</li>
<li>顺滑演示24</li>
<li>顺滑演示25</li>
<li>顺滑演示26</li>
<li>顺滑演示27</li>
<li>顺滑演示28</li>
<li>顺滑演示29</li>
<li>顺滑演示30</li>
<li>顺滑演示31</li>
<li>顺滑演示32</li>
<li>顺滑演示33</li>
<li>顺滑演示34</li>
<li>顺滑演示35</li>
<li>顺滑演示36</li>
<li>顺滑演示37</li>
<li>顺滑演示38</li>
<li>顺滑演示39</li>
<li>顺滑演示40</li>
<li>顺滑演示41</li>
<li>顺滑演示42</li>
<li>顺滑演示43</li>
<li>顺滑演示44</li>
<li>顺滑演示45</li>
<li>顺滑演示46</li>
<li>顺滑演示47</li>
<li>顺滑演示48</li>
<li>顺滑演示49</li>
<li>顺滑演示50</li>
</ul>
</div>
</template>
<script>
import BScroll from 'better-scroll'
export default {
name: "Category",
data(){
return{
scroll:null
}
},
mounted() {
this.scroll = new BScroll(this.$refs.aaa)
}
}
</script>
<style scoped>
.wrapper{
height: 100px;
background-color: #5ea732;
overflow: hidden;
}
</style>
记住 滚的时候要按着鼠标拖,而不是用鼠标滚轮。。
然后,尽量用ref,而且,ref不但可以绑定在组件上还可以在普通元素上(比如div)
ref如果是绑定在组件中的, 那么通过this.$refs.refname获取到的是一个组件对象.
ref如果是绑定在普通的元素中, 那么通过this.$refs.refname获取到的是一个元素对象.
滚动监测
// 默认情况下BScroll是不可以实时的监听滚动位置
// probe 侦测
// 0,1都是不侦测实时的位置
// 2: 在手指滚动的过程中侦测, 手指离开后的惯性滚动过程中不侦测.
// 3: 只要是滚动, 都侦测.
const bscroll = new BScroll(document.querySelector('.content'), {
probeType: 3,
click: true,
pullUpLoad: true
})
监听位置,position位置
bscroll.on('scroll', (position) => {
// console.log(position);//
})
上拉加载更多
- pullingUp
bscroll.on('pullingUp', () => {
console.log('上拉加载更多');
// 发送网络请求, 请求更多页的数据
// 等数据请求完成, 并且将新的数据展示出来后
setTimeout(() => {
bscroll.finishPullUp()
}, 2000)
})
解决框架更改的终极方案:封装
注意,插条要这样放哦,wrapper里面只可以一整个大的东西,所以要再加一个div包住(这个插槽到时候可能会塞很多小东西)
此代码在Scroll.vue组件里,没错封装了。。
<template>
<div class="wrapper">
<div class="content">
<slot></slot>
</div>
</div>
</template>
不要在created里面获取外部信息,要在mounted里面 OK?
100vh代表百分之百的视口的高度
#home{
/*padding-top: 44px;*/
height: 100vh;
}
.content{
height: calc(100% - 93px);
overflow: hidden;
margin-top: 44px;
}
这个样式设计有点烧脑
监听组件,.native
<back-top @click.native="backclick"/>
回到顶部
this.scroll.scrollTo(0,0)
监听位置(优化前)
mounted() {
this.scroll=new BScroll(this.$refs.hhh,{
click:true,
probeType:3
})
this.scroll.on("scroll",(position)=>{
console.log(position)
})
优化后
为什么要这样优化呢,朋友,因为不一定每个界面都需要监听位置,如果像上面一样这样直接赋值3,那么每次调用scroll组件都会回调一次position,影响性能
export default {
props:{
probeType: {
type:Number,
default:0
}
},
mounted() {
this.scroll=new BScroll(this.$refs.hhh,{
click:true,
probeType:this.probeType
})
this.scroll.on("scroll",(position)=>{
console.log(position)
})
}
未解之谜,为什么在scroll组件里面打印不行????????两次都不行!!! why
实现回到顶部小按键在固定位置消失
//第一步传事件和参数position给父组件
this.scroll.on('scroll', (position) => {
console.log(position);
this.$emit('scroll',position)
})
//为事件绑定方法
<Scroll class="content" @scroll="contentScroll">
//布尔值可能会判断为变量,所以搞个变量接收布尔值
isShowBackTop:false
//绑定变量给小组件
<back-top @click.native="backclick" v-show="isShowBackTop"/>
//写方法
contentScroll(position){
this.isShowBackTop=-(position.y)>1000
},
上拉加载更多核心代码
pullUpLoad: {
type:Boolean,
default: false
}
mounted() {
this.scroll=new BScroll(this.$refs.w,{
click:true,
pullUpLoad:this.pullUpLoad
})
this.scroll.on('pullingUp',()=>{
this.$emit('pullingUp')
})
:pull-up-load="true"
@pullingUp="loadmore"
loadmore(){
this.getHomeGoods(this.currentType)
},
因为图片是异步加载的原因,加载需要时间, better-scroll反应不过来那个所有图片的总长度变化,不能及时地改变可滑动长度,其实就是和图片加载速度有关
解决
this.$refs.scroll.scroll.refresh()
解决最大的bug,关于滚动的bug
如何监听图片加载完成了?
- 原生的js监听图片: img.onload = function() {}
- Vue中监听: @load='方法'
事件总线出场
如何将GoodsListItem.vue中的事件传入到Home.vue中
-
因为涉及到非父子组件的通信, 所以这里我们选择了
事件总线
- bus ->总线
- Vue.prototype.$bus = new Vue()
- this.bus.emit('事件名称', 参数)
- this.bus.on('事件名称', 回调函数(参数))
优化
-
问题一: refresh找不到的问题
-
该代码报错
this.$bus.$on('itemImageLoad',() =>{
this.$refs.scroll.refresh()
})
- 第一: 在Scroll.vue中, 调用this.scroll的方法之前, 判断this.scroll对象是否有值
- 第二: 在mounted生命周期函数中使用 this.$refs.scroll而不是created中
- 问题二: 对于refresh非常频繁的问题, 进行防抖操作
该代码执行频繁
this.$bus.$on('itemImageLoad',() =>{
this.$refs.scroll.refresh()
})
- 防抖debounce/节流throttle(课下研究一下)
- 防抖函数起作用的过程:
- 如果我们直接执行refresh, 那么refresh函数会被执行30次.
- 可以将refresh函数传入到debounce函数中, 生成一个新的函数.
- 之后在调用非常频繁的时候, 就使用新生成的函数.
- 而新生成的函数, 并不会非常频繁的调用, 如果下一次执行来的非常快, 那么会将上一次取消掉
debounce(func, delay) {
let timer = null
return function (...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, args)
}, delay)
}
},
有的时候,加上判断更保险(&&)因为它们不一定同时请求到
scrollTo(x, y, time) {
this.scroll && this.scroll.scrollTo(x, y, time)
}
},
finishPullUp() {
this.scroll.finishPullUp()
},
refresh() {
this.scroll && this.scroll.refresh()
}
在better-scroll前提下设置吸顶功能(难点)
1,监听轮播图加载完了没有 2,本来就是父子组件的话,不用设置全局的事件总线??所以事件总线是?
加载一次就够啦!
data(){
return{
isLoad:false
}
},
methods:{
imageLoad(){
if (!isLoad){
this.$emit('swiperImageLoad')
this.isLoad=true
}
}
}
防抖专题
目的:减轻服务器压力 核心:学会等待下一(n)个图片/字符来临,然后一起请求服务器
下面我们看到
- 设置了延时,delay=50
- 而且为什么timer虽然在函数里面,为局部变量还是无法销毁呢??因为函数里面有个闭包操作对它进行了引用。
- 但是不不太能理解里面的arg是什么??
- 还有apply()是什么函数?
mounted() {
const refresh=debounce(this.$refs.scroll.refresh,50)
this.$bus.$on('itemImageLoad',()=>{
refresh()
})
debounce(func,delay){
let timer=null
return function (...args) {
if (timer) clearTimeout(timer)
timer=setTimeout(()=>{
func.apply(this.args)
},delay)
}
}
面试考点
setTimeout里面的函数是异步函数,在下一次事件循环的时候执行,所以就算后面没有写延迟时间,它也会放在后面执行(也就是本身带有延迟时间)
timer=setTimeout(()=>{
func.apply(this.args)
},delay)
//里面的它 函数
()=>{
func.apply(this.args)
}
打印顺序:这个考点涉及到浏览器事件循环
受不了,这个也打印不出来!和之前一模一样的情况!!
refresh() {
console.log('.......')
this.scroll && this.scroll.refresh()
}
吸顶成功了 但是不圆滑,而且两个bar不同步·