SunSeekerX

这条路才刚刚开始啊~

VueTravel

Coding JavaScript 1 评 610 度

使用了vue,vue-route, vuex, vue-awesome-swiper, babel-polyfill, fastclick, iconfont,等最新的前端技术进行开发制作。
webpack进行编译

说明都在文档中文档结构为md语法,网页无法显示目录结构,项目源码就不放了。

项目说明文档

开发之前安装的东西

node.js运行环境

官网:https://nodejs.org/zh-cn/,下载安装长期支持版,直接下一步就行,安装完成之后使用 node -v命令和 npm -v命令参看版本检查是否可用。

码云和git

目前用不到,跳过,可以同步代码,保持线上和线下相同

vue-cli

vue官方提供的脚手架工具
官方地址:https://cli.vuejs.org/
安装1:npm install -g @vue/cli
初始化项目:vue init webpack Travel,如果文件夹已经存在,选择Y,根据提示进行下一步

项目文件介绍

项目文件夹根目录

README.md    项目的说明文件
package.json    项目的依赖包,项目开发所依赖的第三方开发包都包含在里面
package-lock.json package.json的锁文件,可以确定已经安装第三方包的版本
LICENSE    开源协议的说明
index.html    项目默认的首页文件
static 存放静态的资源,比如图片,或者模拟json数据
node_modules 依赖包

src目录

src    整个项目的源代码
src/main.js 整个项目的入口文件
src/App.vue 项目最原始的根组件
src/rounter/index.js 项目所有的路由
src/components/ 存放项目需要用到的组件
src/assets/ 项目需要用到的图片资源

config目录

config/ 存放项目的配置文件
config/index.js 存放基础的配置信息
config/dev.env.js 开发环境的配置信息
config/prod.env.js 线上环境的配置信息

build目录

build/ 存放webpack打包的内容。vue-cli自动构建,一般不用修改
build/webpack.base.conf.js 基础的配置项
build/webpack.dev.conf.js 开发环境的配置项
build/webpack.prod.conf.js 线上环境的配置项

单文件组件与vue中的路由

单文件组件

当一个文件以vue结尾的时候叫做单文件组件,里面放的是一个vue的组件

路由

根据网址的不同,返回不同的数据给用户,这就是路由的功能

项目初始化

设置屏幕大小禁止缩放

<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">

引入两个css初始效果的文件

reset.css 设置每个设备显示的效果是一样的
border.css 解决设置边框多倍屏显示不正常的问题,比如设置了1px的边框,在二倍屏显示为2px

300ms延迟问题

在某些设备使用click事件会出现click延迟300ms执行,
在项目文件夹下使用npm install fastclick --save
进行安装fastclick,安装完成之后在main.js中进行配置
fastClick.attach(document.body)

iconfont字体图标

主要是用到了阿里巴巴的iconfont网站,在网站中新建一个项目

样式辅助工具Stylus

npm install stylus --save
npm install stylus-loader --save
项目安装依赖
<style lang="stylus" scoped>
</style>
在组件中说明使用stylus进行开发

在css中引入stylus全部变量

<style lang="stylus" scoped>
    @import '../../../assets/styles/varibles.styl'
</style>
路径太长可以通过@符号引入,js可以直接使用@,css中需要添加~@
<style lang="stylus" scoped>
    @import '~@/assets/styles/varibles.styl'
</style>

头部区域开发

vue-awesome-swiper轮播图

来源可以在github上搜索vue-awesome-swiper
npm install vue-awesome-swiper@2.6.7 --save
安装vue-awesome-swiper

在js数组中配置图片静态路径的时候需要require
需求:如何components里面的index.vue怎样能把assets里面的图片拿出来。

1.在img标签里面直接写上路径:
<img src="../assets/a1.png" class="" width="100%"/>
2.利用数组保存再循环输出:
<el-carousel-item v-for="item in carouselData" :key="item.id">
    <img :src="item.url" class="carouselImg"/>
    <span class="carouselSpan">{{ item.title }}</span>
</el-carousel-item>
data: () => ({
   carouselData:[
   {url:require('../assets/a1.png'),title:'你看我叼吗1',id:1},
   {url:require('../assets/a3.png'),title:'你看我叼吗2',id:2},
   {url:require('../assets/a4.png'),title:'你看我叼吗3',id:3}
   ]
}),

问题解决Unable to preventDefault inside passive event listener

具体解决链接:[解决地址](https://segmentfault.com/a/1190000008512184)
两个方案:
1、注册处理函数时,用如下方式,明确声明为不是被动的
window.addEventListener('touchmove', func, { passive: false })

2、应用 CSS 属性 touch-action: none; 这样任何触摸事件都不会产生默认行为,但是 touch 事件照样触发。
touch-action 还有很多选项,详细请参考touch-action

[注]未来可能所有的元素的 touchstart touchmove 事件处理函数都会默认为 passive: true

轮播图问题

点击拖动无法继续轮播api同swiper,后期查询修复

ajax请求首页数据

axios的使用

安装axios,npm install axios --save
由于多个组件需要使用ajax发送数据,将发送放在home.vue文件中发送
methods: {
    getHomeInfo () {
        axios.get('./api/index.json')
            .then(this.getHomeInfoSucc)
    },
    getHomeInfoSucc (res) {
        console.log(res)
    }
},
mounted () {
    this.getHomeInfo()
}

请求的代理

在没有后端的情况下,请求的文件放在本地,发布上线不建议修改。
需要webpack下的dev-server提供的请求代理功能
在项目目录下的config目录下面的index.js文件中proxyTable配置代理
比如请求的地址是
axios.get('./api/index.json')
配置文件中填写
proxyTable: {
    './api':{
        target: 'http://localhost:8080',
        pathRewrite: {
            '^/api': './static/mock'
        }
    }
},

图片的显示

由于之前的图片放在asset目录下,在外部请求json文件中的图片地址无法显示,因为无法访问
vue-cli 目录中,只有static 目录放置的静态文件可以被外部访问。如果想在JSON(static/mock/index.json) 中引入图片地址,必须把图片放在static 目录下。然后JSON 中的图片地址,是你的vue 组件引入图片的地址。我是在src/component/home/home.vue中引入 static/img/1.jpg 图片,图片地址为:"../../../static/img/1.jpg"。 在JSON 中的地址也要这样写。如果配置JSON 时不确定图片地址,可以在你对应的VUE组件中 直接 引入一张图片测试下地址,然后再放在JSON 中。

问题待解决

在使用webpack-dev-servser的过程中,配置了本地代理,发现并不是很好用,
时不时会报504的错误,需要多次刷新才可以正确访问到代理的位置,判断是webpack代理的性能问题
![控制台报错截图](说明_files/1.jpg)

ajax获取轮播图默认显示最后一张

在显示的滑块加上判断,v-if判断数组是否有内容,如果还没请求是不会创建滑块的。因为list
创建时默认为空,v-if为false不会渲染
<swiper :options="swiperOption" v-if="list.length">
    <!-- slides -->
    <swiper-slide v-for="item of list" :key="item.id">
            <img class="swiper-img" :src="item.imgUrl" />
    </swiper-slide>
    <!-- Optional controls -->
    <div class="swiper-pagination"  slot="pagination"></div>
</swiper>

建议:使用计算属性来决定是否显示轮播图

<swiper :options="swiperOption" v-if="showSwiper">
    <!-- slides -->
    <swiper-slide v-for="item of list" :key="item.id">
            <img class="swiper-img" :src="item.imgUrl" />
    </swiper-slide>
    <!-- Optional controls -->
    <div class="swiper-pagination"  slot="pagination"></div>
</swiper>

computed: {
    showSwiper () {
        return this.list.length
    }
}

选择地址页面的开发

滑动使用better-scroll

具体使用方法等待后期学习,作用是在浏览器中模拟手机的滑动给人更好的体验效果

兄弟组件之间的联动

通过绑定触摸事件来出发触摸事件,计算高度的方式返回触摸的字母,传递给父组件,
父组件传递给list组件进行页面更新

触摸函数优化

在执行触摸函数的时候函数执行的程度非常频繁,设置定时器减少函数的执行次数提高性能

阻止默认行为

在选择地址的时候滑动字母页面会跟着滚动,在touchstart后面加上prevent阻止默认行为
@touchstart.prevent="handleTouchStart"

选择地址搜索功能的开发

主要技术

使用侦听器,侦听输入数据的改变,触发方法计算父组件传递过来的城市列表
展示相应的数据

首页和选择地址界面的数据共享

采用vuex进行非父子组件的传值

实际开发中一般不采用bus总线的形式进行非父子组件的传值
采用vue官方提供的vuex进行非父子组件中的传值,
vuex介绍地址 [https://vuex.vuejs.org/zh/](https://vuex.vuejs.org/zh/)
state相当与数据创库,组件通过调用api去改变仓库里面的值,
使用仓库数据的组件数据自然也就更新了
介绍图片![](说明_files/1.png)

Vuex的使用

在src目录下新建一个store文件夹,新建index.js文件
创建仓库导出公用变量
在main.js创建根实例的时候传递store,vuex会派发到每个组件里面
子组件通过插值表达式{{ this.$store.state.city }}使用仓库里面的数据

修改仓库里面的数据

给按钮绑定点击事件,点击按钮触发this.$store.dispatch('changeCity', city)
在index.js中actions中定义changeCity方法,参数一: 上下文对象 参数二:传递过来的城市的值
使用上下文对象触发commit方法,调用mutations里面的ChangeCity方法改变store里面的值
    city: '北京'
  },
  actions: {
    changeCity (ctx, city) {
      ctx.commit('changeCity', city)
    }
  },
  mutations: {
    changeCity (state, city) {
      state.city = city
    }
  }
  如果没有异步操作,操作非常简单,组件可以直接调用commit方法改变store里面的数据

修改过后存储到本地

使用localStorage,需要解决用户关闭了本地存储,或者隐身的bug,否则项目无法正常运行
localStorage.city || '北京'
优先从本地取,取不到使用默认,
处理关闭本地存储功能
    localStorage.city = city
  } catch (e) {
  }
  
  
  city: localStorage.city || '北京'
},
mutations: {
    changeCity (state, city) {
        state.city = city
        localStorage.city = city
    }
}
### 拆分store里面的组件
    方便后期维护,对state里面的代码进行拆分
    拆分成为多个js文件
### 使用mapState进行数据映射
    页面引入
    import  { mapState } from 'vuex'
    在计算属性中...mapState(['city'])进行映射
    映射完成  this.$store.state.city  可以改为  this.city
### vuex中的getter
    类似于vue中的计算属性,理解为过滤器,可以对数据进行处理,使用映射记得引入
    
### vuex中的Module
    由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。
    当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

    为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。
    每个模块拥有自己的 state、mutation、action、getter、
    甚至是嵌套子模块——从上至下进行同样方式的分割:
## keep-alive优化网页性能

###  解决路由切换页面的时候ajax重复请求的问题
    在app.vue中使用keep-alive标签包裹路由标签,作用是缓存ajax请求的json文件
    下次页面切换的时候不需要重新请求服务器,减少消耗
### 切换城市首页数据重新加载
    使用了keep-alive组件会多出一个生命周期函数activated
    选择地址过后activated函数会执行,在这个函数判断选择的城市是否和上一次的城市是否
    相同,不同重新请求数据
## 推荐详情页面的开发

### router-link的使用
    为了防止a标签文字颜色发生改变,可以将ui中的li标签直接写成router-link标签
      tag指明渲染成什么标签,依然有点击跳转效果,并且在后面携带了参数
        <router-link
            tag="li"
            class="item"
            border-bottom
            v-for="item of list"
            :key="item.id"
            :to="'/detail/' + item.id"
        >
            <img class="item-img" :src="item.imgUrl" />
            <div class="item-info">
                <p class="item-title">{{ item.title }}</p>
                <p class="item-desc">{{ item.desc}}</p>
                <button class="item-button">查看详情</button>
            </div>
    </router-link>
### 递归逐渐实现详情页列表
    递归组件就是自己调用自己,定义组件的名字就是用来自己调用自己
### 动态获取数据根据id请求对应的文件
    在路由后面配置了每项的id,在发ajax请求的时候可以接收作为参数
    axios.get('./static/mock/detail.json', {
        params: {
            id: this.$route.params.id
        }
    }).then(this.handleGetDataSucc)
###  keep-alive另一种解决
    有些页面需要重新请求ajax,比如详情页面,除了借助actived生命钩子还可以在keep-alive标签上
    使用exclude加上组件名字排除不使用keep-alive进行缓存
    <keep-alive exclude="Detail">
        <router-view/>
    </keep-alive>
## 全局组件的定义

###  全局画廊组件的定义和webpack配置
    在src目录下新建common文件夹新建gallary文件夹,里面存放为gallary的组件
    在build目录下的webpack.base.conf.js文件中配置别名
    resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
            'vue$': 'vue/dist/vue.esm.js',
            '@': resolve('src'),
            'styles': resolve('src/assets/styles'),
            'common': resolve('src/common')
        }
    }
### 画廊组件点击显示
    默认为隐藏点击显示的时候会出现一点问题,
    需要在轮播属性中加上observeParents和observer属性控制
    具体作用可以查询官网api
    [https://3.swiper.com.cn/plus/search.php?kwtype=0&q=obser](https://3.swiper.com.cn/plus/search.php?kwtype=0&q=obser)
    swiperOptions: {
        pagination: '.swiper-pagination',
        paginationType: 'fraction',
        observeParents: true,
        observer: true
    }
### header区域的渐隐渐显效果

## 全局事件的解绑
###  推荐详情页绑定了window事件deactivated事件中进行解绑
    推荐详情页绑定了window事件,如果不进行解绑,会影响其他组件
    比如回到了首页,方法还是会执行原因在于事件绑定在文档对象中
    使用了keep-alive的组件在生命周期会有activated方法页面更新触发
    对应还有deactivated生命钩子函数
    activated () {
        window.addEventListener('scroll', this.handleScroll)
    }
    
    解绑操作
    activated () {
        window.addEventListener('scroll', this.handleScroll)
    },
    deactivated () {
        window.removeEventListener('scroll', this.handleScroll)
    }
## 组件名的作用
###  组件名的作用
    一:可以用来使用递归组件
    二:可以用来取消页面缓存
    三:开发者工具可以显示各个组件的名字
## 动画效果
### 新建Fade.vue文件模板
    模板使用transition标签内部包含slot标签
    vue会自动向这个模板中在特定的时候插入不同的类
## vue项目真机调试
### 局域网调试
    webpack自带的开发服务器默认不支持ip地址访问项目,在局域网下的项目只允许localhost的方式进行访问
    找到项目文件夹下的package.json配置文件修改
    script里面的
    "dev": "webpack-dev-server --host 0.0.0.0 --inline --progress --config build/webpack.dev.conf.js",
    在webpack-dev-server 后面加上--host 0.0.0.0
    这样局域网下面的设备就可以通过ip进行访问了
##  真机测试bug解决
###  低版本安卓机器白屏问题
    某些低版本的安卓手机可能不支持es6的一些特性,需要安装
    npm install babel-polyfill --save
    在main.js文件中引入import 'babel-polyfill'
## vue项目打包上线
###  打包上线
    项目文件夹运行npm run build
    会在项目文件夹下生成一个dist目录需要放到http服务器进行根目录即可运行
    如果需要修改运行路径,比如放在服务器的app目录下,需要修改打包配置重新打包,
    不能直接放到app目录下,文件的引用会出现问题
    在config目录下的index.js文件中最底部修改build内容的代码
    assetsPublicPath: '/',改为
    assetsPublicPath: '/app',
    重新打包编译,项目就会运行在app目录下了
### 组件的异步加载
    适合组件页面比较复杂的情况
    打包出来的js文件实际上是所有页面的js,集合,当我们不需要所有文件的时候就可以按需加载
    主要是app.js文件
    找到src/router/index.js
    修改组件的引用方式,采用箭头函数的方式引入
    component: () => import('@/pages/home/Home.vue')
    component: () => import('@/pages/city/City.vue')
### 打包压缩注意事项
    可以把node_modules文件夹删除,需要进行开发的时候,在项目文件夹中运行npm install就会自动安装需要的依赖
    配置路径需要完整!!!
    assetsPublicPath: '/app/VueTravel/',
    后面不能少了/
    否则出现大问题!

##  遗留bug的解决
### better-scroll滑动安卓无法点击
    项目真机调试发现安卓无法点击,查询问题因为一开始点击事件被禁用了,在使用better-scroll的组件
    初始化的时候加上可以点击
    this.scroll = new Bscroll(this.$refs.search, {click: true})
### 首页无法滑动问题
    这个问题比较新,分析原因在于使用了fastclick插件,当上一次事件未完成,下一次点击开始会阻止
    一开始在全局使用了css属性touch-action:none
    导致页面无法滚动,暂时去除这个属性,等待后续解决
Typora