当前位置: 首页 > news >正文

vue全家桶开发 去哪儿 项目总结

前言

本文记录了项目去哪儿开发过程中需要注意的细节和重点,便于以后查阅,同时进行开源分享

cmd-markdown-logo

 

 

源码和课程教程

项目github开源地址:

github.com/shifengming…

课程地址:

coding.imooc.com/class/chapt…

效果图

 

cmd-markdown-logo

 

cmd-markdown-logo

 

cmd-markdown-logo

 

cmd-markdown-logo

 

cmd-markdown-logo


作者:石小明
链接:https://juejin.im/post/5dd3df0f5188253dbe5ef23a
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

使用的技术栈

Vue:Vue、Vue-router、Vuex、Vue-cli

插件:vue-awesome-swiper、better-scroll、axios

CSS的预处理框架:stylus

api:后台数据接口
复制代码

项目目录

README.md		//项目的说明文件
package.json		//第三方依赖包配置
package-lock.json	//帮助我们去确定安装的第三方依赖包的具体的版本,保持团队编程的统一
LICENSE		//开源协议的说明
index.html	//项目默认的首页
.postcssrc.js	//是对postcss的配置项
.gitgnore	//不需要上传到git上的文件管理
.eslintrc.js	//对代码进行检验,是否标准
.eslintignore	//配置不需要eslintrc检测工具检测的文件
.editorconfig	//配置编辑器总风格统一的自动化格式的语法
.babelrc	//做一些语法的转换,编译成浏览器所能识别的代码
static		//目录下放的是一些静态资源,静态图片,静态数据,和后续模拟json数据
node_modules	//项目中需要用到的第三方node包
src		//放的是项目的源代码
src/main.js 	//整个项目的入口文件
src/app.vue	//整个项目最原始的根组件
src/router/index.js	//项目的路由放置位置
src/components		//项目里要用的一些小组件
src/assets	//项目中需要用到的图片
config		//放置项目配置文件
config/index.js		//放基础配置
config/dev.env.js	//开发环境配置信息
config/prod.env.js	//线上环境配置信息
build		//放置项目打包的webpack配置信息,vue-cli会自动构建
build/webpack.base.conf.js	//基础的webpack配置信息
build/webpack.dev.conf.js	//开发环境的webpack配置信息
build/webpack.prod.conf.js	//线上环境的webpack配置项

项目具体结构

首页部分

iconfont的引入和使用

图片轮播组件的使用

图标区域轮播组件的使用

axios获取接口数据

组件间数据传递

城市选择页面部分

字母表布局

Better-scroll的使用

函数节流实现列表性能优化

搜索逻辑实现

Vuex实现数据共享

locakStorage 实现页面数据存储

Keep-alive 优化路由性能

详情页部分

banner布局

动态路由配置

公共画廊组件拆分

实现fixed header渐隐渐显效果

递归组件实现详情列表

Transition slot插槽实现animation简单动画效果

项目相关的npm依赖包

fastClick:用来处理移动端click事件300毫秒延迟

Stylus: CSS预处理器框架

Stylus-loader

Vue-awesome-swiper:轮播插件

Axios:实现ajax

Better-scroll:scroll插件

设置样式变量

通过variable.styl设置样式变量,抽离出公用样式,以方便维护

项目环境准备

下载node

下载地址(nodejs.org/en/),然后在安装node的时候npm 也被下载下来了

 

cmd-markdown-logo

 

查看node是否安装好

node -v

 

cmd-markdown-logo 在码云上新建一个项目,用来管理代码 cmd-markdown-logo 本地克隆刚才创建的项目 cmd-markdown-logo 使用脚手架Vue Cli使用webpack构建项目

 

npm install -g vue-cli

创建项目

Vue init webpack Travel

运行项目

npm run dev

提交代码

首先使用git status查看仓库状态
然后使用git add . 将代码提交到缓存区
git commit -am “注释”
git push 将代码提交到码云
复制代码

最后在码云上看一下效果

cmd-markdown-logo

 

项目准备

移动端300ms延迟

移动端浏览器click事件为什么会有300ms的延迟呢?因为在手机上有个双击方案 —— 在手机上快速点击两下,实现页面放大;再次双击,恢复到原始比例

那它是如何实现的呢?浏览器在捕捉到第一次点击事件后,会等待一段时间,如果在这段时间内,用户没有再次进行点击操作的话,就执行单击事件;如果用户进行了第二次点击操作的话,就会执行双击事件。这段等待的时间大约300ms

如何解决这个延迟呢?有很多方法,这里推荐两种比较简单的方法

第一种

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1,minimum-scale=1, user-scalable=no">
复制代码
width=device-width 宽度为设备宽度
initial-scale=1 初始比例为1
maximum-scale=1 最大比例为1
minimum-scale=1 最小比例为1
user-scalable=no 用户不能进行放大缩小小
复制代码

第二种

引入第三方库fastclick
复制代码
npm install fastclick --save
因为所有页面都要引入,所以在入口处统一引入就可以了import FastClick from 'fastclick'
FastClick.attach(document.body)
复制代码

1px像素问题

红色边框是用border-bottom: 1px solid red;写的,在手机上明显可以看出它不是1px

cmd-markdown-logo怎么解决这种问题?

 

推荐一种:伪类 + transform

.border1
    height: .5rem
    position: relative
.border1:before
    position: absolute
    top:-.5rem
    left:0
    content: ''
    width:100%
    height:1px
    border-top:1px solid rgba(0,0,0,.3)
    transform: scaleY(0.5)
复制代码

这种方式就是把原先元素的border去掉,然后利用:before或者:after重做border ,并transform的scale缩小一半,原先的元素相对定位,新做的border绝对定位


样式重置

网上有很多reset.css找一份引入到项目中


首页轮播

占位

 

cmd-markdown-logo 图片是可替代资源,在页面显然时,会先将页面中静态的内容渲染上去,等数据返回后,在进行重新渲染,这样页面就会出现抖动,影响用户体验,同时性能也比较低。

 

可以用下面的css代码对这些可替换资源先进行占位,页面大体框架在第一次渲染后就能呈现给用户,数据获取到后,替换相应的内容就可,就不会出现抖动了

.icon-img
    overflow: hidden
    width: 100%
    height: 0
    padding-bottom: 100%
复制代码

样式穿透

 

cmd-markdown-logo 在子组件中实现在这样的布局,需要用到样式穿透,不然是无法滚动下半部分的

 

.icons >>> .swiper-container
  height: 0
  padding-bottom:50%
复制代码

多页

 

cmd-markdown-logo

现在上面的轮播,一页上有8个icon,此时如果需求变成了9个,怎样才能做到在不改动代码的前提下,能实现任意数量的icon

 

可以用计算属性computed对iconList进行监听:

  • 在Home.vue首先定义了iconList:[]通过属性传递给了Icon.vue组件

  • 在Icons.vue中通过props接收到了iconList数据

  • 使用computed之所以能对iconList监听,是因为刚开始传递过来的iconList是空数组,当获取到数据之后,在传递过来iconList是有值得,iconList一旦发生了变化,computed就能捕捉到

  • computed中还有一个计算属性showIconList,它的用途是:

    1,刚开始渲染的时候,由于iconList是一个空数组,直接将空数组渲染上去了

    2,当有了数据之后,又会进行第二次渲染,此时就会看到,轮播始终在最后一页

    3,使用v-if=showIconList是为了不让它在空数组时渲染,而是要等到有数据后在渲染

    4,所以swiper在初次创建是应该要用完整的数据来创建,而不是要空数据创建

代码

<swiper :options="swiperOption">
  <swiper-slide v-for="(page,index) of pages" :key="index" v-if="showIconList">
    <div class="icon" v-for="item of page" :key="item.id">
      <div class="icon-img">
        <img class="icon-img-content" :src="item.iconUrl" alt="">
      </div>
      <p class="icon-desc">{{item.desc}}</p>
    </div>
  </swiper-slide>
</swiper>
computed: {
    pages () {
      const pages = []
      this.iconList.forEach((item, index) => {
        const page = Math.floor(index / 8)          //每页是 8 个,index / 8 能获取到页数
        if (!pages[page]) {     //初始化每一项
          pages[page] = []
        }
        pages[page].push(item)  //变成新数组
      })
      return pages
   },
   showIconList () {
      return this.iconList.length
   }
}
复制代码

城市选择页面

节流

手指在城市字母表中滑动时,会触发无数次handleTouchMove这个函数,这就对性能影响很大

函数节流:通过设定一个时间周期,只要在这个周期内函数就不执行

实现方法

ihandleTouchMove (e) {
  if (this.touchStatus) {
    if (this.timer) {
      clearTimeout(this.timer)
    }
    this.timer = setTimeout(() => {
      const touchY = e.touches[0].clientY - 79
      const index = Math.floor((touchY - this.startY) / 20)
      if (index >= 0 && index < this.letters.length) {
        this.$emit('change', this.letters[index])
      }
    }, 10)
  }
}
复制代码

这里设置的周期是10ms,10ms这个代码只会执行一次,大大优化了性能


keep-alive优化请求

只发送一次请求

每次点击城市或者回到首页时,都会重新发送一个ajax请求,因为当路由切换的时候,这个组件就会被重新渲染,组件一被重新渲染,mounted这个钩子函数就会被执行。这样就会对性能造成比较大的影响

Vue 也考虑到了这一点,为我们提供了一个keep-alive的标签

<keep-alive>
   <router-view/>
</keep-alive>
复制代码

路由的内容被加载过一次之后,就把路由的内容放到内存之中,下次在进这个路由的时候不需要再重新渲染组件了,只需你从内容里把以前的内容拿出来显示就可以了

城市改变再发送请求

按照上面这样优化,当我改变城市时,它也不会发送请求,因为这一块用的是内存里的数据,那么这个选择曾是功能就变得有名无实,那该怎么改进呢?

当我们使用了keep-alive标签后,会自动执行钩子函数activated,而mounted钩子函数是不会被执行的

activated () {
    if (this.lastCity !== this.city) {
      this.lastCity = this.city
      this.getHomeInfo()
    }
}
复制代码

详情页面

全局事件

详情页绑定了一个全局事件,当我在详情页面中滚动,这个样写没有问题,但是当我去到其他页面,在滚动时,你就会发现,刚刚你绑定在详情页中的滚动事件,在这个页面也被执行了,这肯定是有问题的

其实在我们使用了keep-alive标签后,会有两个生命周期函数分别是:activated、deactivated

activated:页面展示的时候被执行

deactivated:页面被隐藏或者页面即将被替换成新的页面时被执行
复制代码
activated () {
    window.addEventListener('scroll', this.handleScroll)
},
deactivated () {
    window.removeEventListener('scroll', this.handleScroll)
}
复制代码

这段代码是页面被展示的执行scroll,页面被隐藏的时候移除scroll事件


递归组件

递归组件就是在我组件的自身去调用组件的自身

如何实现 一级标题,二级标题,三级标题?

data () {
    return {
        "categoryList": [{
            "title": "成人票",
            "children": [{
                "title": "成人三馆联票",
                "children": [{
                    "title": "成人三馆联票 - 某一销售店"
                }]
            }, {
                "title": "成人五馆联票"
            }]
        }, {
            "title": "儿童票"
        }, {
            "title": "学生票"
        }, {
            "title": "特惠票"
        }]
    }
}
复制代码

对一层标题用v-for来进行循环,二、三层标题该怎么显示出来呢?在写组件的时候,都会写一个name的属性,它其中一个用途就是——递归组件

<div
    class="item"
    v-for="(item, index) of categoryList"
    :key="index"
>
    <div class="item-title">
      <span class="item-title-icon"></span>
      {{item.title}}
    </div>
    <div class="item-title-children" v-if="item.children">  //判断是否有数据中是否有 children 这个属性,如果有就使用递归组件
      <detail-list :categoryList="item.children"></detail-list>     //把 children 传给递归组件
    </div>
 </div>
复制代码

如下图所示:

cmd-markdown-logo

 

keep-alive不缓存

在Detail.vue页面中,当我点击了其他景点后,它也是不会发送请求的,那么Detail页面就不会重新渲染了

可以使用keep-alive的exclude属性,给它默认设置为Detail,用途是每次进入Detail页面都会发送请求

<keep-alive exclude="Detail">   //使用 exclude 属性,可以设置不需要缓存的页面
   <router-view/>
</keep-alive>
复制代码

组件中name名字用途

递归组件可以用到

当你相对某个页面想取消缓存的时候会用到

在 Vue 的开发调试工具中会用到
复制代码

webpack

使用alias

项目中有许多地方需要引入一些公用样式,此项目样式是用stylus写了,比如很多地方都需要用到主题色,统一写在一个文件中后期维护很方便。但是引入这个文件很麻烦:

../../../assets/styles/varible.css
复制代码

如果每个页面都这样引入文件,一方面写的不优雅,另一方面维护也不方便

module.exports = {
  ...
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
      'styles': resolve('src/assets/styles')
    }
  }
}
复制代码

在build/webpack.base.config.js文件中找到resolve下alias,它可以对路径进行简化操作,项目中引入这个文件只需要写styles/varible.css即可


路径分配

在自己开发中,经常需要自己moke数据

axios.get('/api/detail.json', {
    params: {
      id: this.$route.params.id
    }
}).then(this.getDetailInfoSucc)
复制代码

这样写路径是访问不到自己mock的数据的,那应该怎么写呢?

axios.get('/static/mock/detail.json', {
    params: {
      id: this.$route.params.id
    }
}).then(this.getDetailInfoSucc)
复制代码

把/api改成/static/mock/这样访问到我们本地的数据了,但是这样有风险的,上线前你需要改回/api,很容易出错,造成bug

module.exports = {
  dev: {
    ...
    proxyTable: {
      '/api':{
        target: 'http://localhost:8080',
        pathRewrite: {
          '^/api':'/static/mock'
        }
      }
    }
 }
复制代码

在config/index.js文件中找到dev下的proxyTable,它可以代理路径,我们在项目中写/api,通过proxyTable可以自动找到/static/mock这个目录


移动端访问

1、在config文件夹中的index.js中的host选项,将本地localhost改为0.0.0.0

cmd-markdown-logo

 

2、在cmd中输入ipconfig查看本地IP

cmd-markdown-logo

 

3、在浏览器中输入IP地址

cmd-markdown-logo

 

4、端口号访问(http://自己电脑的ip地址:8080),将这个网址复制到网页版“草料二维码”中,用QQ扫码访问即可
作者:石小明
链接:https://juejin.im/post/5dd3df0f5188253dbe5ef23a
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

相关文章:

  • 这「五类人」最适合转Web前端,必须要了解的前端工程师
  • 每周分享,前端自学「书籍推荐」
  • 「程序员之路」年轻,总得做些什么吧(致那些还未定型的程序员)
  • 自学入门,省去几万学费,web前端必须要知道的「基础知识」
  • 身为前端,你不得不懂的一些HTTP知识(附赠3道面试题)
  • web前端30个项目列表,学完即可上手做项目
  • 还在羡慕程序员工资高吗?看完这篇前端学习计划,你也可以拿高薪
  • 到达瓶颈的前端业务员思考总结,药到病除,方可突破
  • Nginx热升级流程,看这篇就够了
  • 全栈必经Nginx,不懂 Nginx 的前端不是好前端
  • Webpack实战(一):Webpack打包工具安装及参数配置
  • 前端解决跨域的九种方法
  • 2020年从基础到进阶,测试你有多了解 JavaScript,刷新你的知识!
  • 【面试需要】掌握JavaScript中的this,call,apply的原理
  • 基于ApiBoot的前后分离演示脚手架诞生了
  • Gradle 5.0 正式版发布
  • js数组之filter
  • Less 日常用法
  • SegmentFault 2015 Top Rank
  • vue-loader 源码解析系列之 selector
  • 测试如何在敏捷团队中工作?
  • 浮现式设计
  • 力扣(LeetCode)56
  • 聊聊directory traversal attack
  • 如何学习JavaEE,项目又该如何做?
  • 山寨一个 Promise
  • 为物联网而生:高性能时间序列数据库HiTSDB商业化首发!
  • 源码安装memcached和php memcache扩展
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • 湖北分布式智能数据采集方法有哪些?
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • ​secrets --- 生成管理密码的安全随机数​
  • #android不同版本废弃api,新api。
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (06)金属布线——为半导体注入生命的连接
  • (a /b)*c的值
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (Ruby)Ubuntu12.04安装Rails环境
  • (windows2012共享文件夹和防火墙设置
  • (二)JAVA使用POI操作excel
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (附源码)springboot掌上博客系统 毕业设计063131
  • (力扣)循环队列的实现与详解(C语言)
  • (算法)前K大的和
  • (五)关系数据库标准语言SQL
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)
  • (转)为C# Windows服务添加安装程序
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .jks文件(JAVA KeyStore)
  • .NET Core6.0 MVC+layui+SqlSugar 简单增删改查
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池