(25)性能优化和项目上线 | Vue.js 项目实战: 移动端“旅游网站”开发

复制代码
转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥"前端一万小时"两大明星专栏------"从零基础到轻松就业"、"前端面试刷题",已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。

plain 复制代码
涉及面试题:
1. Vue 提供的事件修饰符是什么?
2. 什么是异步组件?
3. 异步组件工厂的结构是什么?

编号:[travel_25]

1 性能优化

项目进行到这里,我们整个项目的代码编写好像完成了。但其实,后续随着项目变得越来越庞大时,还会有一个可优化的"点"。

❌我们启动服务器,访问项目页面,打开控制台的 Network,选中 "JS",直接来观察一个问题:

从上边的视频中可以看到:当在首页刷新后,页面加载了 app.jsbackend.js 两个 .js 文件。其中 app.js ,就是我们项目中所有页面的业务逻辑代码。所以,当我们从首页再进入详情页/城市选择页时,不会再次加载 JS 文件。

❓这就带来了一个问题:当我们访问首页时,需要一次性加载所有页面的 JS 代码吗?

答:目前我们项目还较小,所以这样的加载方式更好,完全不需要进行拆分(建议当打包后 app.js 至少大于 1MB 时进行异步加载)。

但假设项目变大,那么一次性加载所有页面的 JS 代码就会减低性能。此时,更好的方式就是使用"异步组件"来实现"按需加载"。即,当访问首页时,加载首页的 JS 代码;访问详情页时,再加载详情页的代码。

1️⃣打开 router 下的 index.js

javascript 复制代码
import Vue from 'vue'
import Router from 'vue-router'

/* 1️⃣-①:之前我们在项目中直接引入组件后使用;
import Home from '@/pages/home/Home'
import City from '@/pages/city/City'
import Detail from '@/pages/detail/Detail'
*/

Vue.use(Router)

export default new Router({
  routes: [{
    path: '/',
    name: 'Home',
    // component: Home
    component: () => import('@/pages/home/Home') /*
   																							 1️⃣-②:改为异步组件的形式,component 后
                                                 边不再是组件名,而是一个箭头函数,箭头函数
                                                 返回的值是 Home.vue;
                                                  */
  }, {
    path: '/city',
    name: 'City',
    // component: City
    component: () => import('@/pages/city/City') // 1️⃣-③:城市选择页改为异步加载;
  }, {
    path: '/detail/:id',
    name: 'Detail',
    // component: Detail
    component: () => import('@/pages/detail/Detail') // 1️⃣-④:详情页页改为异步加载;
  }]
})

保存后,返回页面查看。当我们在首页刷新后,会加载 app.jsbackend.js1.js(即首页的 JS 代码);访问城市列表页/详情页时,仅会再加载对应页面的 .js 文件:

当然,除了可以在路由中使用异步组件的形式,只要是 Vue 中的组件,都可以进行异步加载。

例如:

html 复制代码
<template>
  <div>
    <home-header></home-header>
    <home-swiper :list="swiperList"></home-swiper>
    <home-icons :list="iconList"></home-icons>
    <home-recommend :list="recommendList"></home-recommend>
    <home-weekend :list="weekendList"></home-weekend>
  </div>
</template>

<script>
// import HomeHeader from './components/Header'
import HomeSwiper from './components/Swiper'
import HomeIcons from './components/Icons'
import HomeRecommend from './components/Recommend'
import HomeWeekend from './components/Weekend'
import axios from 'axios'
import { mapState } from 'vuex'
export default {
  name: 'Home',
  components: {
    HomeHeader: () => import('./components/Header'), // ❗️异步加载首页的 Header 组件。
    HomeSwiper,
    HomeIcons,
    HomeRecommend,
    HomeWeekend
  },
  
  ...略
}
</script>

2 联调、测试与打包上线

🔗前置知识:

《Node.js 与 NPM 入门:③ NPM 详解》
《首页开发------⑤ AJAX 获取首页数据》

2.1 前后端联调

之前我们编写代码时,实际所有 AJAX 请求的数据都不是后端返回的数据,而是我们自己模拟的假数据。

在实际工作中,当前端页面的代码已全部编写完毕,后端小伙伴也差不多编写完了相关的数据"接口"。

❓双方都编写好了代码,下一步我们前端应该怎么做呢?

答:这时我们就需要把 mock 的数据删除(删除 static 下的 mock 文件夹),去使用后端提供的数据,进行前后端的调试(即,前后端联调)。

在 Vue 中进行前后端联调非常方便,不需要使用类似于 Fiddler、Charles 之类的抓包代理工具。

只需要进行一些配置即可。比如,之前我们在 config 中的 index.js 配置过请求路径:

javascript 复制代码
'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.

const path = require('path')

module.exports = {
  dev: {

    // Paths
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {
      /*
      ❗️当请求 /api 这个路径时,把请求指向本地的 8080 端口,将以 /api 为开头的路径
      替换为 /static/mock。
      */
      '/api': {
        target: 'http://localhost:8080',
        pathRewrite: {
          '^/api': '/static/mock'
        }
      }
    },
    ...略
	}
}

进行联调时,只需要将 taget 指向后台服务器的地址就可以了(如,内网 IP 地址或外网的域名等 )。端口默认为 80 端口,当使用的是 http 协议时,可以省略 :80

2.2 真机测试

当我们项目进行了联调之后,是不是就没有什么问题了呢?

当然不是,我们编写代码时,一直在浏览器运行。当项目运行在真机上后,有时会有一些编写过程中在浏览器上不会出现的 Bug。所以还需要进行"真机测试"。

❓Vue 项目中如何进行真机测试呢?

答:我们的项目启动时是通过 webpack-dev-server 启动的,而它默认不支持通过 IP 的形式访问页面。所以,我们需要修改它的默认项,然后在手机上通过内网的 IP 地址进行访问。

2️⃣打开 package.json

json 复制代码
{
  "name": "qdywxs-travel",
  "version": "1.0.0",
  "description": "A Vue.js project",
  "author": "itsOli",
  "private": true,
  "scripts": { // 2️⃣-①:在 dev 中的 webpack-dev-server 后添加一个配置项 --host 0.0.0.0 ;
    "dev": "webpack-dev-server --host 0.0.0.0 --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "lint": "eslint --ext .js,.vue src",
    "build": "node build/build.js"
  },
  
  ...略
}

2️⃣-②:在终端运行 ifconfig 命令(如果是 Windows 系统,则执行 ipconfig ),找到本机在内网中的 IP 地址;

2️⃣-③:运行 npm run dev 启动服务器,让手机与电脑在同一个局域网内,手机访问本机 IP 地址的 8080 端口;

(以下为 iPhone 6s Plus 机型录制)

通过上边视频可以看到,当手机访问项目时,页面正常显示。首页和详情页功能正常,城市选择页的基本功能正常。但,当手指在字母表滑动浏览城市时,整个页面跟着"滚动"了。

❓如何解决"滑动时,整个页面滚动"的问题呢?

答:我们只需要在代码中添加一个 Vue 中提供的事件修饰符.prevent ,用它来阻止 touchstart 的默认行为即可。

2️⃣-④:打开 city 下 components 中的 Alphabet.vue

html 复制代码
<template>
  <ul class="list">
    <li
      class="item"
      v-for="item of letters"
      :key="item"
      :ref="item"
      @click="handleLetterClick"
      @touchstart.prevent="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
    > <!-- 2️⃣-⑤:在 touchstart 事件上添加 .prevent 修饰符。 -->
      {{item}}
    </li>
  </ul>
</template>

<script>
export default {
  name: 'CityAlphabet',
  props: {
    cities: Object
  },
  computed: {
    letters () {
      const letters = []
      for (let i in this.cities) {
        letters.push(i)
      }
      return letters
    }
  },
  data () {
    return {
      touchStatus: false,
      timer: null,
      startY: 0
    }
  },
  updated () {
    this.startY = this.$refs['A'][0].offsetTop
  },
  methods: {
    handleLetterClick (e) {
      this.$emit('change', e.target.innerText)
    },
    handleTouchStart () {
      this.touchStatus = true
    },
    handleTouchMove (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])
          }
        }, 16)
      }
    },
    handleTouchEnd () {
      this.touchStatus = false
    }
  }
}
</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
.list
  position: absolute
  top: 1.58rem
  right: 0
  bottom: 0
  width: .4rem
  display: flex
  flex-direction: column
  justify-content: center
  .item
    line-height: .4rem
    text-align: center
    color: $bgColor
</style>

小伙伴们自己做真机测试时,因为手机型号不同,可能还会有一些其他的问题。比如,如果是低版本的安卓手机,可能会有手机访问项目出现"白屏"的效果。

产生这样的效果有两种情况:

  1. 手机浏览器默认不支持 Promise;

项目兼容性解决方案:项目目录下安装一个 babel-polyfill 第三方包(它会对浏览器进行判断,如果浏览器没有 Promise,它会自动帮助我们添加这些 ES6 的新特性);

然后在项目入口文件 main.js 中引入即可。

javascript 复制代码
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import fastClick from 'fastclick'
import VueAwesomeSwiper from 'vue-awesome-swiper'

import 'babel-polyfill' // ❗️引入 babel-polyfill。

import store from './store'
import 'styles/reset.css'
import 'styles/border.css'
import 'styles/iconfont.css'
import 'swiper/dist/css/swiper.css'

Vue.config.productionTip = false
fastClick.attach(document.body)
Vue.use(VueAwesomeSwiper)

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})
  1. 当引入 babel-polyfill 后重启项目依然白屏的话,其实不是代码的问题,而是 webpack-dev-server 的问题。解决方案:将项目打包好后,放在真正的开发环境或线上环境中。

2.3 项目上线

现在,我们的项目已经可以上线了。

❓直接把我们项目代码的 src 目录给到后端小伙伴将项目发布上线吗?

答:当然不是,我们在项目中编写的代码,必须经过"打包编译",生成一个能被浏览器运行的代码(代码在打包的同时会被压缩),才能交给后端小伙伴。

3️⃣终端定位到 qdywxs-travel ,运行:

plain 复制代码
npm run build

3️⃣-①:当完成打包后,我们 qdywxs-travel 项目中会多出一个 dist 文件夹,这里边就是我们打包好的项目文件;

3️⃣-②:我们把 build 文件夹给到后端小伙伴即可;

3️⃣-③:后端小伙伴会将这个 build 文件夹里的所有文件拿出来放在后端工程htdocs 目录下(这个目录里包含后端小伙伴编写的 api 接口文件)完成上线。

OK,青山不改,绿水长流,咱们下个项目再见~

祝好,qdywxs ♥ you!

相关推荐
独立开阀者_FwtCoder1 分钟前
前端自适应方案全面解析:打造多端适配的现代网页
前端·javascript·面试
万事胜意50711 分钟前
前端切换Tab数据缓存实践
前端
渣渣宇a12 分钟前
Three_3D_Map 中国多个省份的组合边界绘制,填充背景
前端·javascript·three.js
Anger重名了14 分钟前
🌟新手也能秒懂!协程如何让APP更丝滑?
前端
点正15 分钟前
ResizeObserver 和nextTick 的用途
前端
狗子的狗粮17 分钟前
Node.js 模块加载与 exports 和 module.exports 的区别
javascript
zayyo17 分钟前
Web 应用轻量化实战
前端·javascript·面试
kovli21 分钟前
红宝书第十七讲:通俗详解JavaScript的Promise与链式调用
前端·javascript
lilye6621 分钟前
精益数据分析(19/126):走出数据误区,拥抱创业愿景
前端·人工智能·数据分析
李是啥也不会27 分钟前
Vue中Axios实战指南:高效网络请求的艺术
前端·javascript·vue.js