vue4
axios比ajax更先进:
服务器地址:http://123.207.32.32:8000/home/multidata
安装:
通过url给服务器发送网络请求,用then处理服务器返回的东西:
如果不写method,就默认是get请求方式,如果要改为post:
get传参可以直接写到url里面,也能单独写一个params对象:
如果要发送2个网络请求,等这2个请求都完成后再处理服务器返回结果:
如果不想以数组作为参数接收,而是把服务器数据分别传给res1,res2:
全局配置,利用defaults配置好之后,每一个请求的url前面都会加上http://,每一个请求的超时都被设置为5s
如果不同请求用自己默认的设置,而不考虑全局的,则创建请求对应的示例,第一段代码表示设置这个实例的默认:
如果另外一个请求地址默认是别的地址,则再创建一个实例:
把第三方的插件封装到1个文件中,然后让其他组件引用这个文件,这样当这个插件要换掉时,只用改1个页面即可:
scr新建文件夹network,network下新建request.js文件,第一个参数是用户请求的参数,第二个参数是用户传来一个函数,用于处理请求成功该做什么:
如果main.js要用这个插件:
第二种封装方法:
instance()就会返回promise对象,不用再封装为promise了
拦截器:
在这个实例发送请求时,把请求拦截下来可以做些事情,例如log,然后再return走,继续发送请求,如果没有return,请求就发不过去了:
相应拦截:
在请求回来时,拦截:
大项目:
建立GitHub仓库:
把新仓库拿到vscode中:
把项目create的文件拷贝到clone下来的项目中:
解决红色问题,更新远程仓库:
查看:
或者把本地的仓库直接链接到远程仓库
项目首先要划分目录结构:
注意:assets用于存放资源,其下再新建css和img文件夹,common文件夹用于存储具有公共变量和函数的js文件,components文件夹下新建common文件夹和content文件夹,common用于存放完全公共的组件,外面的项目也能用,而content仅存本项目公共的组件
把素材的normalize.css拷贝到到css文件夹下,为了标准化标签。再把base.css拿过来。
css中:root是获取根元素,此处为html标签,css中通过--来定义变量,后面再通过var()来使用变量
配置别名:
在项目下新建js文件:
为了统一编程风格,比如缩进几个字符,此时把cli2的editorconfig拷贝到项目下:
导航栏
说明:
拷贝tabbar:
把之前的tabBar文件夹拷贝到components的common文件夹下,把mainTabBar文件夹拷贝到content文件夹,因为它仅和项目相关。再把其余的东西拷贝过来,注意此处要.css的后缀不能省略!
把网页图标换了,位于public目录下
定义导航栏组件到components的common文件夹下的navBar文件夹下,设置3个插槽。在home组件里面使用起来。
注意:导航栏在不同的组件中的字体颜色不同,则在哪使用它就在哪个组件中给它设置颜色,如在home中设置字体颜色,和导航栏背景颜色
home组件对外发送请求,获得请求后分发给它的小组件们。由于home组件可能会发送很多请求,所以在network下面再建立一个home.js文件专门用于发送请求。接着在home组件里面通过create函数把请求到的数据拿过来,并分开保存到不同变量中。
轮播图:
说明:
<style scoped>:该vue内部的css样式仅仅对本vue有用,是私有的。
在组件标签写:aa="asd",可以把asd变量传递给该组件定义的aa变量
轮播图从素材的components/common文件夹下的Swiper拷贝过来,由于使用这个轮播图组件的代码有点多,就在views/home下再建立文件夹childCom,childCom专门用于存放Home里面的私有小组件,然后建立一个HomeSwiper组件,通过引用Swiper里面的index.js导入组件,然后使用轮播图组件,然后再把该组件注册到home组件中。网络请求是外面的home组件发的,然后传到HomeSwiper中。注意:如果子组件props的变量是对象或数组,则默认值必须是函数。
推荐:
说明:
推荐模块recommendView,做法类似上面,其中,在childCom再建立RecommendView组件
特色:
说明:
做法类似上面,这个其实是个img,这个img是放在了a里面
导航栏在上下滚动时是不会消失的,所以position:fixed,但这个样式是写到使用导航栏的home组件里的。
ul>li{列表$}*100:可以列出列表1,列表2....列表100
tabControl:
类似上面建立tabControl组件,由于本项目会多次用到,此处把它放到components/content文件夹下。由于这个组件内部都是分为n栏,只是文字不同,那么就不用slot了,而是让文字从外面传进去,在组件里面用v-for显示出来。为了点击哪个哪个就为红色,则一开始就赋值每项一个index属性,再设置一个公共的currentIndex属性,利用currentIndex==index以及点击事件来实现一个是true,其他为false的现象。由于向下滚动到一个时候,这个组件就开始悬浮起来,此时设置position:sticky,top:44px就能实现。
商品列表:
此时请求三类数据,在home。vue建立变量:goods:{
'pop':{page:0,list:[]},
"sell":{page:0,list:[]},
"sell'':{page:0,list:[]}
}
其中每个属性代表一类数据,请求到的数据存到对应的list里面,而page表示当前该请求该类型的第几页数据。
home.js里面新增函数getHomeGoods(type,page)进行请求数据,在home.vue里面进行赋值,此时created函数内代码太多了,新建methods方法转移代码的主要部分。当某一页的数据请求到后,对应的page要+1
要展示数据需要2个组件:GoodsList和GoodsItem,在components/content下建立goods文件夹,再建立这2个组件。外面的home组件把数据传给GoodsList,然后GoodsList利用GoodsItem和v-for显示出来数据,同时再传数据给GoodsItem,在GoodsItem里面把图片,标题,价格,搜藏显示出来。
为了实现点击tabControl可以切换数据,可以利用子传父的emit把currentIndex传到home那里。
滚动:
iscroll和better-scroll是库,可以从上面用一下滚动的库。
使用:better-scroll引入后,要在mounted(){
new BSroll(document.querySelector(‘content’))
}
mounted是在加载完dom元素后调用的,而created是在加载之前调用的
其中内容要长这样,外面有个元素包着它
且这个元素设置高度!!!!且当加载到最后一张图片时要调用它的refresh!!!
这个元素里面只有1个子元素,此处这个元素指的是div:
<div class="content">
<ul>
<li>内容
.....
关于事件监听的使用:
probeType:要不要监听滚动
click:BScroll里面的若有类似按钮的点击事件,则这个点击事件要不要生效
pullUpload:要不要触发上拉加载更多事件
finishPullUp():如果不写的话,只能触发一次上加载更多事件
在A.vue里面,给组件或者标签里面添加ref="aa",可以在A.vue方法体里面通过this.$refs.aa获得这个组件或者标签
css中:height:100vh,表示100%的viewport height
height:calc(100% - 93px)表示父元素内容区的高度-98px,注意如果这个元素设置了绝对定位,则这个就没用了,但是可能出现bug,因为加载问题,子元素可能拿不到父元素的高度,100%就没意义了
把第三方插件better-scroll封装起来到component/common文件下的bScroll文件的BSrcoll.vue里面,该组件放置一个slot,home组件引用它时,把home里面的内容都夹在这个组件标签中。
为了设置根元素的height,还可以通过子绝父相让子元素相对于父元素定位的方法,只设置top和bottom,那么中间的空间就能全占了,以此把content定位到合适位置。但是注意此时的子元素的top和bottom是相对于父元素的,所以class=home的父元素也得设置高度,否则子元素也没有高度。
如果给组件添加类名,则类名最终写到了组件定义的template的根div上
小箭头:
回到顶部:
给组件写监听事件时,要加上.native,比如@click.native,@click表示组件内emit一个"click"事件
滚动组件.scrollTo(0,0,500),可以使得滚动组件(new BScroll出来的)回到顶部(0,0),花费500ms
把这个小组件写到components/content/里面,再装入图片并定位右下角,在定义一个回到顶部事件供home组件调用。
对于props,如果外面的组件标签里面是name=''123',则传给子组件的是字符串123,如果是:name="123",则能看出类型来,传给子组件的是数字123
显示与隐藏:
滚动到某一个地方时才显示出来:
组件内部封装一个方法用于监听滚动,并把postion返回到外面的组件,同时BScroll组件用props接受一个布尔变量,看看父组件要不要监听滚动。父组件利用v-show来显示或者隐藏。
总结参数:
事件触发时,标签内部(如果是组件内部要加.native,否则是接收组件内部emit出来的事件):
传递普通参数:@click="go(123)" ,定义:go(t){}
获得事件对象:@click="go",定义go(e){}
子组件this.$emit("go",t),父组件:@go=“fun”,定义fun(t){}
bug:
A组件向B组件发送事件(通信):在main.js中,Vue.prototype.$bus=new Vue()注册一个$bus, 然后A组件中方法中的this.$bus.$emit('aaa'),在B组件就能监听到:this.$bus.$on('aaa',()=>{}),以此实现A和B组件的通信
图片加载完成会触发load事件。
防抖动:
由于每个图片加载一下都会进行refresh,性能低下,此时需要当第一个图片加载完毕时,它需要等一段时间再refresh,当下一个图片加载完了,它先查看之有没有即将要执行的定时器操作,如果有的话就取消掉之前的refresh,接着自己再等一段时间再refresh。。。。这样到最后也就只有几张图片refresh了。下图的func.apply就是调用函数,...arg表示如果有参数传进来,就存下来,下图中不断调用的refresh()是return的函数,但是用到的timer只初始化了一次。这种结构可以实现初始化一次变量,但后面多次调用函数时,可以共用这一个变量。
我的方法:
可以把debounce再做一次抽取,放到common文件夹下的util,js里面,然后外面的home.vue导入使用它
上拉加载更多:
类似上面,里面的scroll会触发滚动事件,但是把这个滚动事件$emit外面的home来处理。在home里面,再进行axios请求即可,此时list就会多出来东西,这是home显示的东西就更多了。注意为了多次上拉加载更多,需要finishPullUp(),可以再把它封装一下。
bug:
点击tabControl失效了,此时在scroll组件里面,写入click:true
当出现错误提示:Cannot read property 'finishPullUp' of undefined,说明是有了null.finishPullUp,此时用&&解决
tabControl吸顶效果:
利用:组件.$el可以获得组件内部定义的根标签,offsetTop可以获得标签到顶部的距离,但是tabControl需要等待前面的图片加载完毕后获取的offsetTop才是有效的。现在假定只要轮播图图片加载就行,由于有多张图片,此时利用一个布尔变量使得只要有1张图片传过事件来,其他图片就别传了。
可以在home里面再复制一个tabControl,放到NavBar下面,同时监听滚动,利用一个布尔变量,当滚动到某个位置时显示出这个tabControl,父组件要给子组件传递值,可以props,也可this.$refs.子组件.data
离开首页时记录离开的状态:
先keep-alive给router-view让它活着,滚动会出现问题。此时在home组件中利用deactivated记录离开时的scroll.y值到一个变量中,在activated函数中再滚动到这个y值即可。
跳转到详情页:
在goodsItem里面监听点击,然后路由跳转并把图片id传过去,配置路由,再在views下新建detail文件夹,再新建Detail组件,在组件中通过激活的路由显示出来。
详情页的导航栏:
由于导航栏代码稍微多点,在detail文件夹下新建childCom,再新建navDetail组件用于写导航栏,然后设置好样式和点击事件
轮播图:
向服务器发送请求时,再封装一个detail.js,外面把id传入js里面,js通过request发送请求给服务器。然后插入轮播图组件。为了使得一点进来就能创建一个新detail组件,则在keep-alive那里exclude
展示信息,通过建立在detail.js里面封装一个类,目的是让这个类定义属性来分类接受服务器传来的数据,然后在detail.vue里面对请求到的数据存储到类所定义的对象里面,然后再创建一个显示内容的组件,把这个对象传给这个组件并让它显示出来。
店铺信息展示,操作同上
加入滚动效果:利用用scroll把nav下面的包起来就有滚动效果了。同时为了达到悬浮效果,设置nav为相对定位以及它的z-index
新建vue来用来展示商品图片,每张图片load结束后,向detail组件emit事件来让scroll刷新一下高度,具体的刷新延迟优化在common/utils.js里面实现。
参数主题,封装起来
评论主题封装起来
推荐主题封装起来
注意: 组件标签里面 :abC =..,可能不区分大小写,最后传给了组件里面的abc
this.$nextTick(()=>{
})该函数当组件渲染完毕后(不包括组件内的图片渲染完毕),执行
实现点击详情页的主题滚动到对应的地方:先获取点击的index值(子组件emit),detail.vue在图片加载完毕之后获取各个模块的offsetTop并存到一个数组中,当点击某个主题就scrollTo那里。还要对获取offsetTop操作实现防抖。
效果: 滚动到某个主题时,选中对应的标题:
bscroll监听滚动并emit外面,外面detail利用4个offsetTop所在的数组进行判断,然后操纵tab里面的currentindex
封装起来底部的工具栏
回到顶部: 利用混入实现home和detail里面都可以,但是注意混入的周期函数最后与主vue叠加,但是methods是覆盖关系
添加到购物车:detail接收bottomBar发来的点击事件,随后将部分商品信息集成到一个对象中,然后利用vuex管理,此时要安装vuex --save。vuex利用一个数组来存储各类商品,每类商品中有属性count表示该类有多少个商品被添加进去了。然后在cart.vue的navbar中展示出总的个数,其中vuex采用如下目录结构:
将商品列表封装成list组件,然后在list组件中展示更小的item组件,每个对象数据传到item里面,按钮也封装起来。给大的list组件套一个scroll组件便于滚动。
由于有未选中和被选中2种状态,则给每一个添加进购物车的对象一个选中的属性。
当点击时再切换为未选中,同时该布尔值值传给组件内部让它展示按钮的选中和未选中的样式。
再对底部工具栏封装一个组件,该组件有3个div,分别显示3块,按钮采用之前封装过得那个按钮。采用flex来布局。合计价格采用计算属性来计算出来(利用filter和reduce)。
全选效果:如果所有item都选中,则选中,反之:外面组件利用计算属性,根据数组是否有未选中的来得到一个布尔值,然后传到组件里面让它做对应的显示
当点击全选时,若之前为是不全选,则数组中所有对象的属性置为true,若之前已经全选了,则所有置为false
注意本质是在改变对象中的checked属性,外界都围着它转。
购物车弹窗:利用actions.js返回promise对象,当第一次添加进商品时,显示添加成功;当第二次添加时显示商品数量+1。可以利用mapAction往vue里面的methods自动注入方法。
注意:vue.use(toast)会调用toast的install函数
采用插件封装的形式封装Toast弹窗,然后外面直接调动即可:
fastclick解决移动端300ms延迟:
图片懒加载:
把img的src改了:
占位图效果:
代码的10px是css的像素,不是设备的。(pc端等于设备像素)
屏幕尺寸:对角线长度,用于衡量屏幕大小
屏幕分辨率:屏幕像素点的个数,高清屏分辨率大
位图像素:图像的像素
下图是的320*568是设备独立像素
像素密度:
将px单位转化成vw单位:
exclude是忽略某些文件,要使用正则表达式:
windows下部署:
下载Nginx
运行exe:
拷贝dist文件夹过去,然后把dist里面的东西复制到外面:
或者修改配置:
改:
重启nginx:cmd输入 :nginx -s start
远程Linux下部署:
通过ssh登录到远程服务器
yum install nginx
修改配置:
把dist文件夹拷贝过去
访问:
可以借用软件:
vue的响应式原理:
假定此处的obj代表vue中的data,然后遍历里面的属性:先拿到原来的值,然后在defineProperty里面set中监听属性值的改变,若外面vue改变了属性(例如message),
则通知(发布者订阅者模式)所有用到message的地方进行更改;get中只要外界要获取message,则都要调用get方法,get返回原值。
发布者订阅者模式:只要用了message的都是订阅者,把它们放到发布者对象中的一个数组里面,当message要更改时,则遍历订阅者数组让每个订阅者更新一下
图解:
new Vue之后,对data中的每个属性创建对应的开发者,每个开发者有自己的一堆订阅者(每compile一个{{name}}则创建一个订阅者(watcher),然后把它添加到开发者的订阅者数组中),
当某个属性发生了变化,则对应开发者调用notify遍历自己的订阅者,让它们都update。