用Vue开发仿旅游站webapp项目总结 (上)该说的话,该代表的上篇已经代表了。谢谢上篇评论区一些同窗~ 很鼓励我,不过下下篇估计没了,这篇总结完,下下篇可能就是以后学习路的总结记录啦。前端
接触vue不久的朋友应该会有收获。此项目也才是萌新作的第二个Vue项目,使用了脚手架工具(vue-cli2.x非3),前辈老手们有时间看的话,有写得很差的地方还请多多指导!~vue
由于这只是总结操做/思路,没一步步讲代码,仍是先给个官网的图,这样方便看点:webpack
前提假设,在脚手架中,咱们跟路由引入全局的方法一致去在全局中引入Vuex。建立一个文件夹store,在文件夹下建立个index.js脚本。在store/index.js里面写Vuex的一些用法逻辑,而后在入口函数main.js里引入就好了。以下:git
先忽略马赛克...github
在入口函数main.js中引入:web
此时index.js里面的逻辑ajax
以此项目中为例,随着项目的开发,index.js里的逻辑会愈来愈复杂,因此选择拆分。vue-cli
因此,咱们创建两个脚本(state.js、mutations.js)来分别存储这两段代码。npm
而后在index.js中引入:segmentfault
这样拆分完成,简洁很多。
在项目中,以下图用法去取得state里面city的数据,是否是显稍长了点?
Vuex为咱们提供了一个方便的API -> mapState
这样用:
mapState是指,我把State区域里面的公有属性值映射到这个计算属性里。
在这里是:把state里city这个公有属性的值映射到这里的计算属性city里。
这样子的话,就能够把
变成能够直接调用这个计算属性:
...mapState({}/[])这里面能够是数组也能够是对象。是数组的话,那咱们就等于直接给计算属性取名city了,和公有属性的名称同样。
是对象的话,咱们就能够给计算属性自定义取名。
举个...mapState(对象)的例子:
在当前城市这里也能够改:
这里就是传对象给mapState,等于把公有属性city的值映射到计算属性currentCity里。
此时就能够这样用:
这样子就不用写的那么复杂了。
利用Vuex提供的这个API能够简化下列代码:
这样用:
mutations里面是有changeC2()这个函数的(这个命名就....仅当测试,轻喷)。咱们想在组件中调用mutations里的这个函数去改变公有数据区域state里的值,运用mapMutations能够这样简洁地在组件中调用。
这什么意思呢?
mutations里有个叫作changeC2这个方法,这里在该组件的methods中是把这个mutations里的changeC2方法映射到了该组件中methods的changeC2方法里。
...mapMutations()参数也是可接收[]/{}的。
仍是用...mapMutations(对象写法)好理解一点,以下,作个测试:
(乱入的小姐姐~)
这样子写也是能够的。也更容易理解这里的映射。
Getter和Module该项目中都没有用到。
假如咱们想根据state的值,经过一些计算获得新的值的话,就能够用getter来提供新的数据,避免数据冗余。它的定义也和computed同样。
getter能够认为是store的计算属性。就像计算属性同样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被从新计算。
Getter 接受 state 做为其第一个参数,也能够接收其余 getter 做为第二个参数。能够属性访问(store.getters
),能够经过方法访问,也有 mapGetters辅助函数(该辅助函数主要也是映射关系,将store中的getter映射到局部组件的计算属性中)。官方文档给的例子也比较好理解,能够自行看文档。
Module的话,看得勉强理解,Vuex容许咱们将store分割成模块(module)。每一个模块拥有本身的state、mutation、action、getter、甚至是嵌套子模块。
当应用变得很是复杂时,可使用Module避免store对象变得至关臃肿。
我以为Module具体的应用要在复杂项目中亲自练手过才能熟练,目前不敢轻易下手记录,暂且记一笔。
咱们能够在 开发者工具 network 的xhr 中看到
每次咱们路由切换的时候(从Home组件页面跳转到City组件页面或反之的时候)都要发送ajax请求数据。
这样子就重复请求ajax数据了,由于每次路由切换到一个组件的时候,都要从新执行该组件钩子函数,若是该组件有在mounted钩子里请求ajax的话,就每次路由切换都要执行了。这样性能很差。
此时就能够用vue内置的 keep-alive标签来优化。
在全局根组件App.vue中
<router-view>表明的是显示当前路由的组件,而在这个外面加个 vue 内置的 keep-alive标签后,就能够实现这样一个功能:
个人路由的内容被加载过一次以后,个人路由中的内容就都放到内存之中,下一次再进这个路由的内容的时候,就只须要从内存里把之前的内容拿出来就能够了。
此时,无论切换多少次路由,都只有两次ajax数据请求了。
由于使用了keep-alive标签,致使有了新的生命周期函数 activated(keep-alive组件激活时调用)、 deactivated(keep-alive 组件停用时调用)。
以后的路由切换再也不请求ajax数据是由于组件内容是从内存取了不会再从新建立了,对应的mounted钩子函数不会再执行了。
但每次切换、页面从新显示的时候,activated钩子会执行。
此时能够利用这个钩子实现一个需求:
当在列表页选择点击了哪一个城市后,路由切换回到首页时,首页显示的数据是对应着该城市的数据(意味着ajax只请求该城市对应的Home组件页面的数据),而后若是在列表页,选择了与本来在Home页相同的城市的话,就不发送ajax请求新数据。
以前,发ajax请求的时候,是直接这样子发:
实际上,在发送ajax请求的时候,应该带一个参数的。带的这个参数应该是 Vuex 中公有的这个数据。也就是当点击哪一个城市的时候,这个参数就是对应哪一个城市的名称。
怎么在请求中带参数呢?
在请求的链接后面 加上 ?=参数数据
如:
在网页上试一试,发送的参数就在下面
实现需求的思路是:
在每一次页面从新显示的时候(activated钩子函数触发)咱们判断此时页面上的城市是否和上一次显示的城市相同 若是不相同 就发送ajax请求
而后咱们设置个空字符串 lastCity (当作一个中间缓存值用于判断)
紧接着,当页面挂载完毕的时候,咱们给它赋予当前页面的城市数据。
而后在页面更新的时候,判断上一次的 this.lastCity 的值 是否等于 更新后的 this.city 的值。若是不等于的话,就发送新的ajax请求,请求相应city的数据,若是等于的话就不发送。
此时,经过keep-alive新增的生命周期钩子函数以及lastCity这个缓存值就实现了咱们要的功能了。
先看个gif说明此功能啥样:
就这个玩意儿。这个就是画廊。上面有轮播,下面有页码。
由于这不只仅只有一个页面会用到,可能之后不少页面都会用到,因此 写个全局公用的组件Gallary.vue。
须要在详情页的一个组件 Banner.vue 里面去使用这个公共组件
gallary用fixed占满全屏。
利用flex布局,让这个以下wrapper区域垂直居中
而后使用 Vue-awosome-swiper第三方插件,先放入两张图
而后给那个.wrapper定义个宽高100%。按照以下这种写法的话width先有个100%的宽度了而后height也100%的意思是针对于这个width的宽度来讲的,因此这里定义了这个100%的height的意思是这个height与width的宽度相等 意思是一个正方形。
此时页面:
咱们让图片按比例自适应这个正方形,再把wrapper下的背景颜色去掉,此时两张图片能够正常显示轮播了:
而后加页码,其实这个页码就是该插件的按钮区和配置参数一块儿控制的。先加上按钮区代码:
vue-awesome-swiper这个插件是基于swiper实现的,这里面的配置参数好比 pagination 能够去 swiper 官网找的。
咱们去官网找找看能不能找到配置咱们页码需求的参数(固然是能找到的,否则我还写个啥...):
因而可知,这个页面的翻页样式就是对应这个paginnation中的paginationType 中的 fraction。
如今来配置参数,首先在swiper上加上 :options="swiperOption"。
而后在data里配置。先把按钮区配置出来:
再把paginationType ‘fraction’ 分式 给配置出来
如今就有了,但在小小的地方,审查元素才能够看见
本来框架的样式,经过审查元素找出这里是绝对定位。
那么咱们这样改bottom -1rem就好了?
那确定是不行的...
这里有个坑,当感受代码没写错,页面却没达到预期的时候,就是再次审查元素的时候了...审查元素发现这个插件组件有个swiper-container里还定义了个overflow: hidden。
因此咱们在画廊组件里穿透做用域来改掉这个样式就行
画廊逻辑部分很简单就跳过不记录了,不过有个坑仍是值得提一下。
在画廊自身的组件gallary.vue里测试功能的时候都好好的,可是gallary这个公有组件是要在详情页的Banner.vue组件中引入的。
那么问题就来了,当咱们在Banner组件对应的页面一会儿点进去gallary组件对应的页面的时候,轮播插件会出现一个计算宽度高度的问题。以下gif图这样:
要解决这个问题,须要在gallary的轮播插件配置参数中加上这两个配置参数
加上这两个参数的意思是:
我这个swiper插件,只要监听到我这个元素,或者父级元素变化的时候(这个监听的就是swiper和swiper的父级元素),这个插件会自动地自动刷新一次,从新计算宽高。
经过此次自我刷新,就能够解决轮播插件的这个计算宽度高度的问题。(这些配置参数在swiper官网均可以查到怎样用的)
看个gif。
仅提这段,当手指往下滑的时候,逐渐显示清晰以后一直清晰的div景点详情框逻辑。
这个逐渐显示清晰的这块是用个div框来fixed定位写的。
一开始v-show不显示这个div框而且让该div框的opacity为0,在activated钩子函数中检测全局scroll(window.onscroll)事件(即检测滚动条的状态,滚动条一旦动了就触发scroll事件),当触发scroll事件时,执行一个方法,此方法里面写逻辑。写的逻辑是:当滚动条往下滑动60px外时让这个div框的v-show参数为true而且经过公式
let opacity = document.documentElement.scrollTop / 140
来让该div框随着越往下滑动清晰度越高,而后在这条语句下面限制opacity透明度值为1:opacity = opacity > 1 ? 1 : opacity
。
显而易见:document.documentElement.scrollTop
的意思是获取当前页面的滚动条纵坐标位置。
这样功能实现了,但还有个很重要的坑。对全局事件的解绑。
在header区块逻辑中,咱们在activated钩子中定义了个全局scroll事件。
由于这个是全局事件,因此咱们在其余组件中也能够监测到。这样很容易引起一系列严重的隐藏的bug。
因此咱们应该在detail下header.vue组件中对该组件解绑:
对应keep-alive引用而可使用的钩子还有一个deactivated钩子。该钩子在页面即将被替换成新的页面的时候触发。
因此这里咱们利用deactivated钩子和removeEventListener函数来解绑全局事件。
举个例子,list组件的name: 'DetailList'。在list组件模板中想要使用递归组件调用自身时,就要根据name的值来用做标签(detail-list)调用。以下:
假设有个Detail.vue组件,其name: ' Detail'。当想要keep-alive全局组件时,Detail.vue组件对应的页面,路由从新切换到这个页面不用去内存中取缓存值,能够利用Detail组件的name的值以下使用:
这样等因而除了Detail.vue组件,其余组件均可以拥有设置keep-alive后的功能。
如上图红框里的组件名称,这里的名称就取决于设置的组件的name属性的值。
举项目中例子说明,注意下图红框中的值
此时咱们应该获取的是,动态路由中 id为0002的参数的数据。
这样设置后,其实动态路由中,会把对应的参数存在 这个变量id里。
每次请求,但愿把这个id带给后端,就能够这样写:
如今能够在network的XHR里看见咱们发送给后端的请求中附带了 id
前面只写接口名 后面这样子写(咱们把参数放到params去了):
设置的动态路由,只是动态加了个id参数并不能自动让页面也跟着动态显示数据,动态显示数据还得靠ajax请求数据。
而目前这个组件是在mounted钩子中执行ajax请求的,而且该组件有keep-alive的做用影响着。这样当路由跳转到id为0003/0004...页面的时候,组件也只会从内存中取出第一次进入该组件某个id的页面。并不能根据id对应显示页面。
怎样经过ajax请求而动态显示数据呢?有两种方法,两种方法上面都提到过。
在列表页选择某个城市,路由自动跳转回首页后,首页须要显示的是该城市对应的数据这里记录过。(提示一下:利用activated钩子,判断参数id是否等于以前的id,若是不等则从新执行ajax请求。)
组件中name属性的三个做用中的第二个做用已经说出了解决方案。
这两种方式留给读者自行思考,想不通的能够参考下我github该仓库里的代码。src/pages/detail/Detail.vue
来看个gif
这就是路由跳转页面会带来的影响。会把当前页面(Home.vue)的屏幕的显示的宽高 带到 咱们跳转到的页面(Detail.vue)上去。形成如上gif所示现象。
这样来解决。
这个在官方文档中称为 路由的滚动行为。
咱们如今是想让每次路由切换进入到下一个页面的时候滚动在顶部显示。 继续看文档。
把这段代码复制到路由配置项中:
这样就实现咱们预期的需求。
通常等后端数据写好后,咱们就再也不使用本身前端模拟的数据,而是去使用后端给过来的数据来调试。
若是要访问服务器上的数据的话,要在配置文件config/index.js下的proxyTable里把target改成服务器的地址(能够写内网的IP地址 或 外网的域名都行)。而后改pathRewrite的话,就见实际状况数据存放在服务器的哪一个文件夹下了。
这里的前端的项目是经过 webpack-dev-server 启动的,默认不容许经过ip来访问内部服务器。因此咱们须要把默认的配置项作修改。
想让这个 webpack-dev-sever 可以被ip访问的话,须要这样配置下:
(貌似漏点了... 其实也不要紧....)
而后这里真机测试的时候,有时候就会遇到一些在PC上开发时发现不了的bug以及要考虑兼容性。这个就要各人根据实际状况来改了。
vue-cli 2.x中,就能够在项目目录下执行指令 npm run build
,此时Vue的脚手架工具会帮咱们自动地对src目录下源代码进行打包编译生成一个能被浏览器运行的代码,同时这个代码也是压缩事后的代码。
打包完成后会生成一个dist文件夹,给到后端开发人员,或者直接把static文件夹里的内容扔到后端服务器根目录上就OK了。这只是基本的操做,想要改变访问路径或怎样的操做,就各位小伙伴本身去找了,有心自会找到~
这篇文章仅是在这个项目中对于我我的而言以为能够总结记录下来的,更具体更详细的知识和流程,感兴趣不妨去imooc支持一下DellLee老师的这门课程~
有部分地方代码量太多不方便贴出来,想参考代码学习的能够进我Github。
但愿也能帮到大家~