- 专家问诊,提供专业建议
- 急速响应,体验省心
- 根据需求灵活定制解决方案
如何用Vue构建大型单页面应用?
标签:- 2017-8-18 作者:Lfdhjbsufvycn
服务端:Node.js
前端框架:Vue (v2.x)
前端构建工具:webpack
代码检查:eslint
状态管理:Vuex
服务端通信:axios
进程管理:pm2
首先先说一下单页面的优缺点:
单页面开发的优点:
良好的用户体验
用户不需要重新刷新页面,减少TTFB的请求耗时,获取数据也是通过Ajax异步获取,页面显示流畅。
前后端分离
前端负责界面显示,后端负责数据存储和计算,各司其职,不会把前后端的逻辑混杂在一起。
减轻服务端压力
减轻服务器压力,服务器只需要提供API接口,不用管页面逻辑和页面的拼接,吞吐能力会提高几倍。
共用一套后端程序代码,适配多端
同一套后端程序代码,不用修改就可以适用于Web、手机、平板。
单页面开发的缺点:
首屏加载过慢
单页面首次加载,需要将所有页面所依赖的css和js 合并后统一加载,所 以css和js文件会较大,影响页面首次打开时间。
SEO
因为页面数据都是前端异步加载的方式,不利于搜索引擎的抓取。
基于以上的原因,所以我们引入了Vue SSR技术
引入Vue SSR
服务端预渲染
vue2.0引入了虚拟DOM,实现原理就是vue的编译器在编译模板之后, 会将这些模板编译成一个渲染函数,也就是render方法, 函数被调用的时 候就会渲染并且返回一个虚拟DOM的树,在交给一个patch函数,把虚拟 DOM施加到真实的DOM上。这样做的主要原因是因为js的运算是非常快 的,而在浏览器中直接操作DOM会对性能有一定损耗。
流式渲染
服务端渲染支持流式渲染,因为http请求也是流式的,在渲染组件时返回一个可读的 stream 流,然后直接写入 到 HTTP 响应中。流式渲染 能够确保服务端的响应度,也能让用户更快地获得渲染内容。
对组件进行缓存
前后端复用一套代码
前端和服务端可以复用一套代码,提升开发效率和维护性Vue SSR流程图
从图中可以看出,ssr有两个入口文件,client-entry 和 server-entry.js 也就是客户端和服务端入口文件,都包含了同一套应用代码,webpack 通过两个入口文件分别打包成给服务端用的 server bundle 和给客户端用的 client bundle. 当服务器接收到了来自客户端的请求之后,会创建一个渲染器 bundleRenderer,这个 bundleRenderer 会读取上面生成的 server bundle 文件,并且执行它的代码, 然后发送一个生成好的 html 到浏览器,等到客户端加载了 client bundle 之后,会和服务端生成的DOM 进行对比,也就是判断这个DOM 和自己即将生成的DOM 是否相同,如果相同就将客户端的vue实例挂载到这个DOM上, 否则会提示警告。
|— api api 接口文件
|— assets 静态资源目录
|— components vue组件
|— filters 过滤器文件
|— router 路由文件
|— views 页面模板文件
|— utils 工具方法目录|— store vuex相关文件
|— app.js vue入口文件
|— client-entry.js 客户端入口文件
|— server.entry.js 服务端入口文件
|— index.html HTML入口文件
开启Vue SSR
使用服务端框架 express 或 koa
服务端框架,我们使用的是express,之前也使用过了koa,有了一些未知的坑,koa是不错,但是生态圈不如express,express有不少比较有特色的模块并不支持koa,并且官方的例子使用的就是express,所以我们为了方便就选择了express作为我们的ssr服务器。
安装配置webpack 和 vue
拆分入口文件,服务端和浏览器要分开渲染
vue2使用了虚拟DOM, 因此对浏览器环境和服务端环境要分开渲染, 要创建两个对应的入口文件。
server-entry: 使用 vue ssr 功能将虚拟DOM渲染成网页client-entry: 使用 $mount 直接将应用挂载到DOM上server-entry 服务端入口文件
server.js 返回一个函数,该函数接受一个从服务端传递过来的 context 的参数,将 vue 实例通过 promise 返回。 context 一般包含 当前页面的url,首先我们调用 vue-router 的 router.push(url) 切换到到对应的路由, 然后调用getMatchedComponents 方法返回对应要渲染的组件, 这里会检查组件是否有 preFetch 方法,如果有就会执行它。
在then里会将服务端获取到的数据挂载到 context 对象上,后面会把这些数据直接发送到浏览器端与客户端的vue实例进行数据(状态)同步。
client-entry 客户端入口文件
客户端入口文件很简单,同步服务端发送过来的数据,会和服务端生成的DOM 进行对比,也就是判断这个DOM 和自己即将生成的DOM 是否相同,如果相同就将客户端的vue实例挂载到服务端渲染的DOM上, 否则会提示警告。
组件化
将组件分为:基础组件、业务组件、页面组件
基础组件:
与业务低耦合,可复用
业务组件:
与业务深耦合,复用难度大,难抽象
页面组件
页面是组件的容器,将组件组合可以形式一个完整的界面├── components
│ ├── business # 基础组件
│ └── base # 业务组件
├── header
├── header.vue
├── logo.png
├── header.scss
├── views # 页面组件
│ ├── index
├── index.vue
└── comment
Vue的组件引入构建工具之后有一个单文件组件概念。就是眼前的这个Vue文件,在同一个Vue文件里,可以同时写 模板、脚本 和 样式,三个东西放在一个里面。 使用webpack进行打包,编译成js模块。可以使用多种预处理器Babel、ts、sass、postcss,同时可以使用方便的热重载。
在Vue中,父子组件之间的通信是通过 props 传递。从父向子单向传递;每次父组件更新时,子组件的所有 prop 都会更新为最新值。
如果想要子组件把数据传递给父组件,就需要在子组件上绑定自定义事件,然后在子组件使用emit去派发事件但开发中大型项目会遇到以下的问题
多个视图依赖于同一状态
兄弟组件间的状态传递无能为力
传参的方法对于多层嵌套的组件将会非常繁琐
所以这个时候,我们需要用Vuex负责多组件的状态管理Vuex
Vuex 是专门为 Vue.js 设计的状态管理库
结合Vue实现页面的展示更新
统一页面状态管理以及操作处理
Vuex 使用 单一状态树,通俗理解就是一个应用的数据集合,可以想象为一个“前端数据库”,让其在各个页面上实现数据的共享,并且可操作从左到右,从组件出发,组件中调用 action,在 action 这一层级我们可以和后台数据交互,比如获取初始化的数据源,或者中间数据的过滤等。然后在 action 中去派发 Mutation。Mutation 去触发状态的改变,状态的改变,将触发视图的更新。
Vuex项目结构
├── index.html # HTML模板
├── app.js
├── api # API配置文件
├── components # 组件
└── store
├── index.js # 入口文件,提供store的module构建└── modules
├── index.js # 首页模块
├── list.js # 列表模块
└── common.js # 通用模块
使用单一状态树,导致应用的所有状态集中到一个对象中。所以当应用变得很大时,store对象会变得臃肿不堪为了解决以上问题,Vuex 允许我们将 store 分割到模块(module)。每个模块拥有自己的 state、mutation、action、getters,让代码结构更清晰, 多人开发时,每个人只需要负责开发自己的模块即可。
state:单一状态树
getters:状态的获取
mutations:触发同步事件
action:提交mutation可以包含异步操作
数据处理
Axios
现在vue-resource,现在官方宣布不在维护,
所以我这里使用的是Axios,它能够同时支持客户端和服务端请求,拦截请求和响应,支持 Promise API,客户端支持防止 CSRF 攻击,并且可以处理并发请求。
我们在项目里,主要 利用拦截器做预处理,对API进行封装,并且讲述下在组件中如何进行使用利用拦截器做预处理
请求时的拦截器
请求完成后的拦截器
对API进行封装
对 服务端 和 客户端 API请求文件进行区分
要点:服务端 需要在headers里写入cookie
在组件中的使用
随着我们代码,项目越来越大,优化必不可少,下面介绍一下我们的优化策略优化策略
serviceWorker 预缓存
在serviceWorker进程中运行
缓存必要的 JS、CSS、font
大幅度减少CDN的压力
资源是持久性存储
和indexDB、LocalStorage共用,存储空间约有50M
使用常规的方式,用LocalStorage来缓存JS以及CSS,会与业务代码耦合性很高,并且十分容易被XSS攻击,但使用serviceWorker不会有这样问题,我们只需要关注需要缓存的文件即可,缓存文件的安全全部由浏览器自行控制,用户无法手动删除这些缓存。
唯一的缺点就是,目前有些浏览器还不支持serviceWorker,只能等浏览器自行支持我们可以使用webpack插件来实现
npm install --save-dev sw-precache-webpack-plugin服务端API数据的缓存
组件的缓存
按需分块加载
后面会单独写一篇文章,来介绍和讲解下使用方法和原理通用策略
将静态资源上传到CDN
使用Gzip压缩
图片压缩、懒加载和base64
首屏外使用异步加载
优化后,我们的项目的首页加载时间从700多ms,提升到了400多ms
软件开发暂无最新文章查看全部推荐文章>
推荐人才
免责声明:
网站文章均由网站用户自行通过本网站系统平台投稿编辑整理发布,仅供学习与参考, 不代表本网站赞同其观点和对其真实性负责。如有侵犯您的版权,请联系我们,我们将及时删除。