Webpack开发可复用的单页面富应用学科,前端闲聊

重型单页面应用的进阶挑战

2015/09/30 · HTML5,
JavaScript ·
单页应用

原稿出处: 林子杰(@Zack__lin)   

翻阅须知:此处的巨型单页面应用(SPA Web
App)是指页面和成效组件在一个某部量级以上,举个栗子,比如
30+个页面100+个零件,同时伴随着大量的多寡交互操作和几个页面的数据同步操作。并且那里涉及的页面,均属于
hash 页面,而多页面概念的页面,是一个单独的 html
文档。基于那一个前提,大家再来商讨,否则我怕我们 Get 不到同一个 G 点上去。

前者发展与现状

大家都通晓前端是由HTML、CSS、Js组成的,一开头这么写出来的页面,不可能有些加载,复用性对比差,重复工作比较多。微软就推出了ifram标签,就是相当于在网页中嵌套一个网页,切换目录只是切换ifram中的网页,依旧间接加载某个完整的html界面。接着ajax的出现,完毕了部分刷新,优化了用户体验。后来进来了jQuery时代,jQuery封装了累累原生方法,缩短了代码量。现在我们前端进入了左右端分离时代,流行
MV* 框架(MVC、MVP、MVVM),MVVM框架有Angular、Vue、React。

美高梅开户网址 1

MVVM框架

近日大家后台管理种类是基于Vue开发的单页面应用(SPA)。

正文先发于TalkingCoder,一个有逼格的程序员社区。转发请声明出处和作者。

本文版权归新浪和作者吴双本人共同享有 转发和爬虫请评释原文地址
www.cnblogs.com/tdws

挑衅一:前端组件化

按照大家所说的前提,第四个面对的挑战是组件化。那里如故要强调的是组件化根本目标不是为了复用,很几个人历来没想明白那一点,总是认为造的车轱辘其余事情可以用,说不定将来也可以用。

骨子里前端发展迭代这么快,交互变化也快,种种适配更新司空见惯。前几天造的轮子,过阵子别人造了个高级轮子,我们都会选更尖端的车轱辘,所以现在前端界有一个面貌就是为着令人家用自己的轮子,自己努力不停地造。

在前端工业化生产趋势下,假若要拉长生产效用,就必须让组件规范化标准化,达到怎么样的水准吗?一辆车除了底盘和车身框架需求自己安插创设之外,其余标准零件都可以购买组装(专业学得差,有吗谬误请指正)。也就是说,除了
UI
和前端架构要求协调解决之外,其余的机件都是足以推广拿来主义的,如果打算让车子跑得更稳更安全,可以对组件进行打磨优化完善。

说了那般说,倒不如看看徐飞的篇章《2015前端组件化框架之路》 里面写的内容都是通过一定实践得出的想法,所以一大半内容本身是协助而且深有体会的。

Vue简单介绍

1、Vue.js是一个构建数据驱动的web框架
2、Vue.js落成了多少的双向绑定和组件化
3、Vue.js只需求关周到据的变更,无需繁琐的取得和操作dom
譬如给一个元素绑定事件并赋值,jQuery的做法是:

<input class="ipt" type="text">
<button class="btn"></button>
<script type="text/javascript">
$.ready(function () {
        $('.ipt').value();
        $('.btn').click(function() {    
        })
 })
</script>

vue的写法是:

<input class="ipt" v-model="value" type="text">
<button class="btn" @click="click"></button>

.vue文件的写法

<template>
    这里写HTML
</template>
<script type="text/ecmascript-6">
    这里写数据和方法
</script>
<style lang="stylus" rel="stylesheet/stylus">
    这里写css
</style>

写在前方

一.写在眼前

项目上线有一段时间了,一个依照webpack+vue+ES6的手机端多页面使用。其实说是多页面使用,实际上在webpack中属于八个app,
 要是真是做纯单页面,那应该有二三十个页面吗。所以自己那里的多页面使用,是分为多个SPA。比如微信最上面,有多少个导航,微信,通讯录,发现,我。
那么那三个导航,就是本身的多少个SPA,配置四个输入即可。

在此地就背着太多代码了,项目协会将会放到github上,地址在背后给出,以供参考,上传的光景只是一个索引加上配置情状,其实关键点也就在webpack.config.js了,那里最主要安排了entry,loader,plugins,output目录啥的。

在那里先附上package.json和webpack.config.js吧:

 

美高梅开户网址 2美高梅开户网址 3

 1 {
 2   "name": "my-web",
 3   "version": "1.0.0",
 4   "description": "desc",
 5   "main": "index.js",
 6   "scripts": {
 7     "test": "echo \"Error: no test specified\" && exit 1",
 8     "start": "webpack-dev-server --inline --hot",
 9     "dev1": "webpack-dev-server --open",
10     "dev": "webpack-dev-server --inline --hot",
11     "build": "set NODE_ENV=production&&webpack"
12   },
13   "author": "ws",
14   "license": "ISC",
15   "devDependencies": {
16     "babel-core": "^6.24.1",
17     "babel-loader": "^7.0.0",
18     "babel-plugin-transform-runtime": "^6.23.0",
19     "babel-preset-es2015": "^6.24.1",
20     "babel-runtime": "^6.23.0",
21     "css-loader": "^0.28.4",
22     "extract-text-webpack-plugin": "^2.1.0",
23     "glob": "^7.1.2",
24     "html-webpack-plugin": "^2.28.0",
25     "jquery": "^3.2.1",
26     "node-sass": "^4.5.3",
27     "sass-loader": "^6.0.5",
28     "slideout": "^1.0.1",
29     "style-loader": "^0.18.2",
30     "url-loader": "^0.5.8",
31     "vue": "^2.3.3",
32     "vue-croppa": "^0.1.0",
33     "vue-hot-reload-api": "^2.1.0",
34     "vue-html-loader": "^1.2.4",
35     "vue-ios-alertview": "^1.1.1",
36     "vue-loader": "^12.2.1",
37     "vue-resource": "^1.3.3",
38     "vue-router": "^2.7.0",
39     "vue-style-loader": "^3.0.1",
40     "vue-template-compiler": "^2.3.3",
41     "vue-touch": "^2.0.0-beta.4",
42     "webpack": "^2.6.1",
43     "webpack-dev-server": "^2.4.5"
44   }
45 }

View Code

 

美高梅开户网址 4美高梅开户网址 5

  1 var path = require('path');
  2 var webpack = require('webpack');
  3 // 将样式提取到单独的 css 文件中,而不是打包到 js 文件或使用 style 标签插入在 head 标签中
  4 var ExtractTextPlugin = require('extract-text-webpack-plugin');
  5 // 生成自动引用 js 文件的HTML
  6 var HtmlWebpackPlugin = require('html-webpack-plugin');
  7 var glob = require('glob');
  8 
  9 var entries = getEntry('./source/**/*.js'); // 获得入口 js 文件
 10 var chunks = Object.keys(entries);
 11 console.log('输出chunks', chunks);
 12 module.exports = {
 13     entry: entries,
 14     output: {
 15         path: path.resolve(__dirname, 'public'), // html, css, js 图片等资源文件的输出路径,将所有资源文件放在 Public 目录
 16         publicPath: '/public/',                  // html, css, js 图片等资源文件的 server 上的路径
 17         filename: 'js/[name].js',         // 每个入口 js 文件的生成配置
 18         chunkFilename: 'js/[id].[hash].js'
 19     },
 20     externals: {
 21         jquery: "$",
 22         EXIF: "EXIF",
 23         wx: "wx"
 24     },
 25     resolve: {
 26         extensions: ['.js', '.vue'],
 27         alias: {
 28             'vue': __dirname + '/lib/vue/vue.js',
 29             //'vue-alert': __dirname + '/lib/vue-alert/vue-alert.js'
 30         },
 31     },
 32 
 33     module: {
 34         loaders: [
 35             {
 36                 test: /\.css$/,
 37                 // 使用提取 css 文件的插件,能帮我们提取 webpack 中引用的和 vue 组件中使用的样式
 38                 //loader: "style-loader!css-loader",
 39                 loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' })
 40             },
 41             {
 42                 // vue-loader,加载 vue 组件
 43                 test: /\.vue$/,
 44                 loader: 'vue-loader',
 45                 options: {
 46                     //解析.vue文件中样式表
 47                     loaders: {
 48                         // Since sass-loader (weirdly) has SCSS as its default parse mode, we map
 49                         // the "scss" and "sass" values for the lang attribute to the right configs here.
 50                         // other preprocessors should work out of the box, no loader config like this necessary.
 51                         //'scss': 'vue-style-loader!css-loader!sass-loader',
 52                         //'css': 'vue-style-loader!css-loader!sass-loader',
 53                         //'js': 'babel-loader',
 54                         //'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
 55                         css: ExtractTextPlugin.extract({ fallback: 'vue-style-loader', use: 'css-loader' }),
 56                         //exclude: [
 57                         //    path.resolve(__dirname, ""),
 58                         //    //path.resolve(__dirname, "app/test")
 59                         //]
 60                         //exclude:'/source/course/course-detail/course-detail.css'
 61                     }
 62                     // other vue-loader options go here
 63                 }
 64             },
 65             {
 66                 test: /\.js$/,
 67                 // 使用 es6 开发,这个加载器帮我们处理
 68                 loader: 'babel-loader',
 69                 exclude: /node_modules/
 70             },
 71             {
 72                 test: /\.(png|jpg|gif|svg)$/,
 73                 // 图片加载器,较小的图片转成 base64
 74                 loader: 'url-loader',
 75                 query: {
 76                     limit: 10000,
 77                     name: './imgs/[name].[ext]?[hash:7]'
 78                 }
 79             }
 80         ]
 81     },
 82     plugins: [
 83         // 提取公共模块
 84         new webpack.optimize.CommonsChunkPlugin({
 85             name: 'vendors', // 公共模块的名称
 86             chunks: chunks,  // chunks 是需要提取的模块
 87             minChunks: chunks.length
 88         }),
 89         // 配置提取出的样式文件
 90         new ExtractTextPlugin('css/[name].css')
 91     ]
 92 };
 93 
 94 var prod = process.env.NODE_ENV === 'production';
 95 module.exports.plugins = (module.exports.plugins || []);
 96 if (prod) {
 97     module.exports.devtool = 'source-map';
 98     module.exports.plugins = module.exports.plugins.concat([
 99         // 借鉴 vue 官方的生成环境配置
100         new webpack.DefinePlugin({
101             'process.env': {
102                 NODE_ENV: '"production"'
103             }
104         }),
105          new webpack.optimize.UglifyJsPlugin({
106              compress: {
107                  warnings: false
108              }
109          })
110     ]);
111 } else {
112     module.exports.devtool = 'eval-source-map';
113     module.exports.output.publicPath = '/view/';
114 }
115 
116 var pages = getEntry('./source/**/*.html');
117 for (var pathname in pages) {
118     // 配置生成的 html 文件,定义路径等
119     var conf = {
120         filename: prod ? '../views/' + pathname + '.html' : pathname + '.html', // html 文件输出路径
121         template: pages[pathname], // 模板路径
122         inject: true,              // js 插入位置
123         minify: {
124             removeComments: true,
125             collapseWhitespace: false
126         },
127         hash:true
128     };
129     if (pathname in module.exports.entry) {
130         conf.chunks = ['vendors', pathname];
131         //conf.hash = false;
132     }
133     // 需要生成几个 html 文件,就配置几个 HtmlWebpackPlugin 对象
134     module.exports.plugins.push(new HtmlWebpackPlugin(conf));
135 }
136 
137 // 根据项目具体需求,输出正确的 js 和 html 路径
138 function getEntry(globPath) {
139     var entries = {},
140         basename, tmp, pathname;
141 
142     glob.sync(globPath).forEach(function (entry) {
143         basename = path.basename(entry, path.extname(entry));
144         tmp = entry.split('/').splice(-3);
145         pathname = tmp.splice(0, 1) + '/' + basename; // 正确输出 js 和 html 的路径
146         entries[pathname] = entry;
147     });
148     console.log(entries);
149     return entries;
150 }

View Code

 

开发工具使用的VS2017,本来使用WS,不过用习惯VS的我或者受不了,毕竟17依然皇太后强大了呗。既然是vue项目,那数据请求肯定就是vue-res,
路由就是vue-loader,编译es6大家都是babel。 下边是序列结构预览:

美高梅开户网址 6美高梅开户网址 7美高梅开户网址 8他们分别是图表资源,引用库资源,发布打包后的js和css,src源码和包裹后的html

挑战二:路由去中央化

据悉大家所说的前提,中央化的路由维护起来很坑爹(要是做一七个页面 DEMO
的就没要求出来现眼了)。MV*
架构就是存在这么个坑爹的题目,必要申明宗旨化 route(angular 和 react
等都急需先注明页面路由协会),针对差其他路由加载哪些组件模块。一旦页面多起来,甚至一旦有人偷懒直接在某个路由写了部分业务耦合的逻辑,那些route 的可维护性就变得多少不好了。而且用户访问的率先个页面,都亟需加载
route,即便其它路由的代码跟当前页面毫不相关。

大家再回过头来思考静态页面简单的加载情势。大家只要把 nginx 搭起来,把
html 页面放在对应的静态资源目录下,启动 nginx 服务后,在浏览器地址栏输入
127.0.0.1:8888/index.html
就足以访问到那几个页面。再复杂一点,大家把目录整成上边的花样:

/post/201509151800.html /post/201509151905.html /post/201509152001.html
/category/js_Webpack开发可复用的单页面富应用学科,前端闲聊。base_knowledge.html /category/css_junior_use.html
/category/life_is_beautiful.html

1
2
3
4
5
6
/post/201509151800.html
/post/201509151905.html
/post/201509152001.html
/category/js_base_knowledge.html
/category/css_junior_use.html
/category/life_is_beautiful.html

那种目录结构很熟吧,对 SEO
很融洽吧,当然那是后话了,跟我们前天说的不是一次事。那种目录结果,不用大家去给
Web Server 定义一堆路由规则,页面存在即重回,否则重回404,完全不须求多余的讲明逻辑。

据悉那种目录结构,大家可以抽象成那样子:

/{page_type}/{page_name}.html

1
/{page_type}/{page_name}.html

实在还能更简便:

/p/{name}.html

1
/p/{name}.html

从组件化的角度出发,还足以那样子:

/p/{name}/name.js /p/{name}/name.tpl /p/{name}/name.css

1
2
3
/p/{name}/name.js
/p/{name}/name.tpl
/p/{name}/name.css

所以,根据大家简化后的逻辑,我们只须要一个 page.js
那样一个路由加载器,依据大家约定的资源目录结构去加载相应的页面,大家就不须求去干表明路由并且中央化路由那种蠢事了。具体来看代码。咱也懒得去分析了,里面有注释。

类型布局

├── build // 构建相关
│ ├── build.js
│ ├── check-versions.js
│ ├── dev-client.js
│ ├── dev-server.js
│ ├── utils.js
│ ├── vue-loader.conf.js
│ ├── webpack.base.conf.js
│ ├── webpack.dev.conf.js
│ └── webpack.prod.conf.js
├── comm// 打包后生成的目录
│ ├── favicon.ico
│ ├── index.html
│ └── static
├── config // 配置相关
│ ├── dev.env.js
│ ├── index.js
│ └── prod.env.js
├── package.json //开爆发产信赖
├── server //服务及mock数据
│ ├── controller
│ └── mock
├── src //源代码
│ ├── App.vue // 入口页面
│ ├── api // 所有请求
│ ├── assets // 字体等静态资源
│ ├── common // 全局公用方法
│ ├── components // 全局公用组件
│ ├── favicon.ico
│ ├── index.html // html模板
│ ├── main.js // 入口js 加载组件 伊始化等
│ ├── pages // 所有页面
│ ├── plugins // 全局工具
│ ├── router // 路由
│ └── store // 全局store管理
美高梅开户网址 ,└── static // 第三方不打包资源
├── async.js
├── css
├── img
├── jquery-1.8.3.min.js
├── jquery.ztree.js
├── md5.js
├── paopao.js
├── spark-md5.js
├── tinymce
├── upload.js
├── upyun-mu.js
└── vue-style-loader

正文为浩如烟海作品,总共分四节,提议按顺序阅读:

二.几点紧要的取得

1.组件化开发爽啊,
调用者只须要关注输入和输出,代码明朗,简单保险

2.vue-res promise异步风格太美丽,博尔济吉特·布木布泰喜欢了。然而有坑,ios8.x,使用基本浏览器运行js,
不支持promise语法,所以需求在入口中,import多少个npm下载的node
module:

 npm i whatwg-fetch core-js es6-promise –save-dev

 美高梅开户网址 9

3.记得此前做一个有线电话端项目,完全没有自动化,种种页面间跳转慢的一比,一点也不流畅,项目布局不便于管理,重复代码更加多。

 近百个页面js版本得不到控制,管理js,css引用困难。微信静态资源缓存如此惨重,没有版本控制,每个页面js版本的改动要人命。

4.化解缓存问题,应明令禁止html缓存,由于使用extract-text-webpack-plugin,可以确保你html入口中只有简单的几行代码,等着自动化帮您引入所需js,所以尽管禁止html缓存,也不会影响响应速度,毕竟大家的html文件
     也就1-2k左右.html禁止缓存的原故是预防,js更新后,js
hash版本已改变,但浏览器缓存的html中,依然是请求旧版本js文件,这样一来js版本控制变得没有意思。

  1. js调用手机雕塑,
    调用安卓手机拍照不易于啊,所以如果只想在微信上行使网页的话,提议采纳微信js SDK。

6.
IPhone和各自安卓手机,使用原生input调用录像后,图片到页面中会出现旋转问题,所以在微信上
使用js sdk, 在任何浏览器上,就用EXIF.js  手动将其旋转90度
或者180度举办校正。

7.推荐一款mobile用的正确性的弹窗组件
vue-ios-alert.  ios风格的弹窗。地址以及github:  
 http://isay.me/vue-ios-alertview/example/![](https://images2017.cnblogs.com/blog/686162/201709/686162-20170904231146210-1849602734.png)

 

8.手机上的 日期
时分秒选取器,推荐一个有坑的货
 https://github.com/k186 
有坑哦,使用的话,请看closed的首个issue。别的日期接纳仍然相比推荐原生。加上时分秒的话原生的也许就糟糕用。美高梅开户网址 10

9.页面touch切换tag 使用的一个vue-tab
 github找一找,ios8不辅助flex-shrink,要选用-webkit-flex-shrink。

  1. 上拉加载越多用的vue-loadmore,侧方滑动菜单 使用了jquery的slideout

11.
万一路由相比多以来,提出路由单独分一个js配置,并且一定要按需加载,否则打包文件太大。如若是用户点击率极高的路由,可以直接require进去。

12.片段js库,就不要通过require了,直接在html引入进来算了,毕竟这么些库基本不会变动,也没要求决定版本

13.前端AOP,
 vue-res的拦截器点个赞,我能够在拦截器中,为本人每一个呼吁
都添加authentication
header等信息,像用jq的时候,我只好手动把ajax包装一层

14.像微微数据的加载,文字方面,最好预先给出加载中那种唤醒,不可以给空白。列表的加载
要多着想加载中,加载成功和暂无数据的处理。见过不少app和网页都是进入到列表页,首先一个暂无数据的背景图给出去 
       了,结果稍等一下,数据又加载出来了….

15.即使已经组件化了,但自我还指出有一个每个页面公用必要require的js,我一般都叫application.js
 在这里 可以放一些您的常量,枚举,公共措施,helpers,utils,ajax
等配置,并且在此地可以import footer header vue-res vue-alert
等片段各类组件或者页面都亟待来说的零部件

16.热交替是必须的,比原先用gulp
livereload方便

17.手机端页面调试,推荐vConsole(去github找)。
示例:美高梅开户网址 11美高梅开户网址 12

18.因而babel编译es5的都没问题.。
 我有个独立的小作用,没用es6,直接谷歌(谷歌(Google))调试开发,结果到了ios9.x上
 不援救也不报错,将来幸免踩进去吧。上面是代码:

美高梅开户网址 13

19. IOS上总计时间 需求new Date(‘2017/09/09’)的格式,
 而无法采用横杠的格式

挑衅三:领域数据大旨化

对于单向数据流循环和数据双向绑定哪个人优什么人劣是永远也啄磨没结果的问题,要看是何等工作场景什么工作逻辑,如若这些前提没统一好说吗都是徒劳无功。当然,这么些挑衅的前提是非后台的单页面应用,后台的前端根本就不要求考虑前端内存缓存多少的拍卖,直接跟接口数据库交互就行了。明确了那些前提,大家随后研讨哪边叫世界数据焦点化。

面前议论到三种多少绑定的法子,但是只要频仍跟接口交互:

  • 内存数据销毁了,重新请求数据耗时浪费流量
  • 倘诺多少个接口字段部分分歧只是选拔情况一样
  • 七个页面一向有一些的多寡一致,不过先来后到导致某些计数字段不同
  • 多少个页面的数额一致,其中一些数据发生用户操作行为导致数据爆发变更

由此,大家须求在作业视图逻辑层和数目接口层中间扩展一个
store(领域模型),而以此 store 需求有一个集合的 内存缓存 cache,那一个cache 就是中央化的多寡缓存。那那一个 store 究竟是用来弄啥勒?

美高梅开户网址 14

Store 具有多形态,每个 store
好比某一类物品的蕴藏(领域,换个词简单明白),如蔬果店 fruit-store,
衣裳店
clothes-store,蔬果店可以放苹果香蕉黑木耳,衣服店可以放西服三角裤人字拖。借使品种过于繁多,我们得以把蔬果店精细化运营变成香蕉专卖店,苹果专卖店(!==
appstore),甚至是木耳专卖店…( _
_)ノ|,蔬果种类不一样等,不过也都是称重按斤卖嘛。

var bannerStore = new fruitStore();

var appleStore = new fruitStore();

有了这么些囤积之后,大家可以放心的把多少丢给视图逻辑层大胆去用。想修改数据?直接让
store 去改就行了,其余页面的 DOM
文本内容也得修改吧?这是其余页面的事体逻辑做的事,大家把事件抛出去就好了,他们处不处理那是她们的事,咱别瞎操心(业务隔离)。

那么 store 具体弄啥勒?

美高梅开户网址 15

  • 32
    个赞地方可点赞或者撤回,多个页面的赞数须求联合,按钮点赞与裁撤的情景也要一起。
  • 条目是不是已收藏,废除收藏后 Page B 需要删除数据,Page A+C
    必要共同状态,若是在 Page C 又有窖藏操作,Page B
    必要相应增减数据,Page A 状态须求联合。
  • 发评论,Page C 需求立异评论列表和评价数,Page A+B
    需求更新评论数。倘诺 Page B 没有被加载过,那时候 Page B
    得到的数额应该是流行的,须要联合给 A+C 页面对应的多少开展立异。

就此,store
干的活就是数量状态读写和一道,假设把数量状态的操作放到各种页面自己去处理,页面一旦多了或者复杂起来,就会生出各样页面数据和情景恐怕不平等,页面此前双向引用(业务耦合严重)。store
还有另一个功力就是数码的输入输出格式化,简单举个栗子:美高梅开户网址 16

  • 别的接口 API 再次回到的数码,都急需通过 input format
    举行统一格式化,然后再写入
    cache,因为读取的多少已按照大家约定的规范开展的拍卖,所以大家运用的时候也不必要理会接口是回到如何的数据类型。
  • 某些零部件需求的数据字段格式可能不一样,若是把数量处理放在模板进行处理,会造成模板不能越发从简通用(业务耦合),所以必要output format 举行处理。

之所以,store
就是扮演着那样的角色——是数码状态读写和协同,以及数额输入输出的格式化处理。

此处来概括讲一下src文件

《Vue+Webpack使用规范》

三.局地缺点

 1.脑子抽风啊,分为三个SPA,
整套项目下来,感觉依然应当做一个SPA。毕竟SPA之间切换,一个SPA切换来另一个SPA
如故加载东西孝庄多,不够流畅。固然微信浏览器缓存“严重”

2.类型社团划分依然不够合理,但觉得也还是能应付用。

3.组件化没有发挥到极致,自己vue组件间通讯没办好,md找子组件,我竟然还有通过遍历的方法。

4.有些组件用的jquery的,搭配的不是很流畅,导致个别操作强行使用dom操作。

5.自我有多少个条件,开发,测试,demo, 线上。
每一趟公布到一个环境
 都亟待改了陈设后,重新打包,很痛心啊,关于这点有怎样好的法子呢? 

挑战四:Hybrid App 化

现在 Hybrid App 架构应用很火啊 _
(:3」∠)_,不搞一下都不好意思说自己是做 H5的。那里所说的 Hybrid App
可不是那种内置打包的 html 源码这种,而是径直去服务端请求 html
文档那种,可能会选取离线缓存。有的人觉着只要要使用 Hybrid
架构,就无法动用 SPA 的办法,其实 Hybrid 架构更应当利用 SPA。

相见的多少个问题,我差不离列举一下:

  • 客户端通过 url 传参

    若是经过 http get 请求的 query 参数进行传参,会导致命中不到 html
    文档缓存,所以经过 SPA 的 hash query 传参,可以规避这一个题材。

  • 与其余 html 页面举行跳转

    那种气象下,进入新页面和重回旧页面导致 webview 会重新加载本地的
    html 文档缓存,视觉体验很不爽,即便页面使用了离线缓存,而 SPA
    可以避开这一个题目。

  • 使用了离线缓存的页面须要协理代码多版本化

    由于使用了非覆盖性资源公布办法,所以须求仍旧保留旧的代码一段时间,以幸免用户使用旧的
    html
    文档访问一些按需加载成效或免除了本地缓存数据而拿不到旧版本代码。

  • js 和 css 资源 离线化

    鉴于离线缓存的资源需求先在 manifest
    文件宣称,你也不容许总是手动去维护要求引用的 js 和 css
    资源,并且那多少个按需加载的成效也会为此错过按需加载的含义。所以须要将
    js 和 css 缓存到
    localstorage,直接省去这一步维护操作。至于用户清除
    localstorage,参考第三点解决方案。

  • 图标资源离线化

    将图标文件举办 base64 编码后存入 css 文件,方便离线使用。

api 和 views

我们企业后台项目如今几乎有十多少个api模块。随着业务的迭代,模块会越加多。所以这里按照工作模块来划分pages,并且将pages
和 api 多个模块一一对应,方便维护,如下图

美高梅开户网址 17

aip和pages.png

如此无论项目怎么累加,api和pages比较好维护。

《Vue+Webpack开发可复用的单页面富应用学科(配置篇)》

四.写在结尾

 那些项目产品将持续支付,可是下一阶段还有个种类,我将使用一个SPA落成,关于vue有怎样好的各个mobile组件,希望dalao不吝推荐。

 

 

借使,您觉得读书那篇博客让你有些收获,不妨点击一下右下加【推荐】按钮。
如果,您愿意更易于地窥见自家的新博客,不妨点击下方灰色【关怀】的。
因为,我的分享热情也离不开您的任天由命辅助。

感谢您的读书,我将持续输出分享,我是蜗牛,
保持学习,谨记谦虚。不端不装,有趣有梦。

挑衅五:性能优化

@前端农民工 在 别处 已经说得很驾驭了,直接传送门过去看吗,那里不罗嗦了。

 

1 赞 2 收藏
评论

美高梅开户网址 18

components

此间的components放置的都是大局公用的一部分零部件,如上传组件,富文本等等。

美高梅开户网址 19

components.png

《Vue+Webpack开发可复用的单页面富应用学科(组件篇)》

store

vex要基于须求去选择,我们后台项目以来,就算事情模块比较多,还有权力,但业务之间的耦合度是很低的,所以根本未曾须要选用vuex来储存data,每个页面里存放自己的data就行。当然有些数据照旧要求用vuex来归并保管的,如登录,用户新闻,如故用vuex管理有利于。

《Vue+Webpack开发可复用的单页面富应用学科(技巧篇)》

Router

路由那些概念开首是在后台出现的,浏览器发出请求,服务器按照请求,解析url路径,按照服务器的路由配置,重返相应
html 字串。大家前端路由的贯彻精神上就是检测 url 的浮动,截获 url
地址,然后解析来匹配路由规则,每趟 hash 值的变更,会触发 hashchange
这一个事件,通过轮换 DOM
的办法来贯彻页面的切换,还有通过HTML5的三个api,pushState 和
replaceState落成记住路由。

在上一节中,我们介绍了在档次https://github.com/icarusion/vue-vueRouter-webpack中有关webpack的部分基础配置,包蕴支付环境和生产条件,在本节中,大家器重介绍使用Vue.js和vue-router,通过组件化的法门来开发单页面富应用的相关内容。读者可以clone或下载那个类型,结合具体代码来看本文。

router-view

<router-view> 是用来渲染路径匹配到的组件。<router-view>
仍是可以内嵌<router-view>,完结路由嵌套。

 <keep-alive>
        <router-view v-if="$route.meta.keepAlive"></router-view>
 </keep-alive>

基础知识扫盲

最后

前几天自我只是给我们一句话来说了一晃后台管理的构造和vue的简练知识,大家只要有趣味可以去询问一下,也可以每一日交换~

本段主要介绍一些前端的功底概念,老司机可以一直跳过。

单页面富应用(SPA)和前端路由

单页面富应用(即Single Page Web
Application,以下简称SPA)应该是新近几年火起来的,尤其是在Angular框架诞生后,很多SPA的网站以及基于Electron或Ionic的桌面App和移动App家常便饭,比如Teambition。

SPA的为主即是前端路由。何为路由呢?说的通俗点就是网址,比如www.talkingcoder.com/article/list;专业点就是历次GET或者POST等请求,在服务端有一个特意的正则配置列表,然后匹配到具体的一条路子后,分发到区其余Controller,然后进行各个操作后,末了将html或数额重返给前端,那就形成了三次IO。当然,如今半数以上的网站都是那种后端路由,也就是多页面的,那样的裨益有众多,比如页面能够在服务端渲染好直接回到给浏览器,不用等待前端加载任何js和css就可以一直显示网页内容,再比如说对SEO的亲善等。那SPA的弱点也是很扎眼的,就是模板是由后端来保安或改写。前端开发者须要设置任何的后端服务,必要还得上学像PHP或Java那个非前端语言来改写html结构,所以html和数据、逻辑混为一谈,维护起来即臃肿也麻烦。然后就有了上下端分离的支出格局,后端只提供API来回到数据,前端通过Ajax获取到数量后,再用自然的方法渲染到页面里,这么做的亮点就是内外端做的业务分的很明亮,后端专注在数据上,前端专注在互相和可视化上,从以前后搭配,干活不累,若是之后再付出移动App,那就刚刚能动用一套API了,当然缺点也很扎眼,就是首屏渲染需求时刻来加载css和js。这种支付情势被过多公司认可,也油不过生了过多前端技术栈,比如以jQuery+artTemplate+Seajs(requirejs)+gulp为主的支付情势所谓是万金油了。在Node.js出现后,那种情况有了校勘,就是所谓的大前端,得益于Node.js和JavaScript的语言特色,html模板可以完全由前端来支配,同步或异步渲染完全由前端自由支配,并且由前端维护一套模板,那就是干什么在服务端使用artTemplate、React以及即将生产的Vue2.0缘故了。那说了那般多,到底怎样算是SPA呢,其实就是在内外端分离的底子上,加一层前端路由。

前者路由,即由前端来爱戴一个路由规则。达成有三种,一种是利用url的hash,就是常说的锚点(#),JS通过hashChange事件来监听url的改观,IE7及以下要求用轮询;另一种就是HTML5的History形式,它使url看起来像一般网站那样,以”/”分割,没有#,但页面并不曾跳转,可是使用那种方式须要服务端帮衬,服务端在接到到独具的伏乞后,都针对同一个html文件,不然会产出404。所以,SPA唯有一个html,整个网站有着的始末都在那几个html里,通过js来处理。

前者路由的助益有无数,比如页面持久性,像大多数音乐网站,你都可以在播放歌曲的还要,跳转到其他页面而音乐没有间断,再譬如前后端彻底分手。前端路由的框架,通用的有Director,更加多照旧构成具体框架来用,比如Angular的ngRouter,React的ReactRouter,以及大家前面用到的Vue的vue-router。那也拉动了新的付出形式:MVC和MVVM。近年来前端也能够MVC了,那也是为啥那么多搞Java的钟爱于Angular。

支出一个前端路由,主要考虑到页面的可插拔、页面的生命周期、内存管理等。

编纂可复用的代码、模块化、组件

编纂可复用的代码是对编程质地的一个呈现。写一个通用工具函数、维护一个目的,这么些都足以说是可复用的,不过我们那里切磋的,紧若是运用CommonJS规范来进行模块化开发。那代码复用和模块化有怎么样关联呢,其实模块化的一个原因就是能够使代码复用,你付出的模块可以提须要其别人用,一个模块可以是小到一个布署文件,也可以大到一个日历组件。把一个页面拆分成不一样的模块,然后来组装,那样既能升高开销效能,又有利于维护。那组件又是怎么着吗?如若说模块化是一种开发格局,那组件就是那种形式的切实落实。比如一个Button按钮、一个输入框,或者一个上传控件都可以打包为一个组件,在接纳的时候,可能只用写一行,就能落成文件上传成效,甚至足以支撑拖拽上传、大小和格式限制等。那么些组件具体怎么支付呢,那就是本文前边重点探究的内容了。

Vue的路由和它的组件化

在项目https://github.com/icarusion/vue-vueRouter-webpack中,我们运用的技术栈是vue.js+vue-router+webpack,其中webpack的功力早已在上篇小说中详尽介绍了。在说vue-router在此之前,我们先聊聊Vue的零部件。

零件的协会

Vue的组件可以说是Vue中最神奇也是最难懂的有的了,这一部分懂了,vue也就懂了。vue组件的风味是可插拔、独立功效域、观察者方式、完整的生命周期。大家来看一个零部件的为主构成:

Vue.component(‘child’, {    props: [‘msg’],    template:'{{ msg }}’, 
  data:function(){return{            title:’TalkingCoder’}    },   
methods: {// …},    ready:function(){    },   
beforeDestroy:function(){    },    events: {// …}});

一个零件基本跟一个vue实例是近乎的,也有投机的methods和data,只然而data是透过一个function来回到了一个目的,具体原因可以查阅vue的文档。

props是从父级通过html特性传递来的数目,它可以是字符串、数字、布尔、数组、对象,默许是单向的,也足以安装为双向绑定的。props里的参数能够直接通过像this.msg这种艺术调用,那与data的里的数据是同一的。

template是以此组件使用的html片段,可以直接是字符串,也得以像’#child’那样标识一个dom节点。

ready和beforeDestroy是四个常用的生命周期,ready是在组件准备好时的一个回调,一般在此地大家得以选用获取数据、实例化第三方组件、绑定事件等,beforeDestroy正好相反,是在组件即将被销毁时接触回调,在那里我们销毁自定义的实例、解绑自定义事件、定时器等。

什么样使用组件

组件一般是由它的父级来突显调用的,比如上边的child组件,我们就足以在父级中运用:

newVue({    data:
{        msg1:’Hello,TalkingCoder’,        msg2:’你好,TalkingCoder’}})

上例使用了四回child组件,使用props传递了一个参数msg,并且首个零部件的参数是双向绑定的,在双向绑定后,无论修改父级依然子元素的msg,双方的多少和view都会响应到,而单向绑定后,子组件修改是不会潜移默化到父级的。

在渲染完,的内容就会交替为组件template内的字符串了,固然使用的是同一个child组件,不过五回使用的成效域是单独的,那也是干吗在组件内data要动用function来回到一个对象的原委。

父子组件间的通讯

在Vue.js中,父子之间的通讯紧要透过事件来成功,这种就是大家耳熟能详的观看者形式(或叫订阅-发表格局),很多框架也都选用了那种设计方式,比如Angular。父组件通过Vue内置的$broadcast()向下播放事件和传递数据,子组件通过$dispatch()向上派发事件和传递数据,双方都足以在events对象内接收自定义事件,并且处理各自的业务逻辑。

父组件使用了多少个相同子组件,怎么着区分呢?诸如我们地方的demo使用了一遍child组件,可是什么来分裂那四个吗,也就是说如若给child广播事件,怎么样给其中指定的一个广播呢,因为广播后,它俩都会收取到事件的。大家可以利用v-ref来标识组件:

newVue({    data:
{        msg1:’Hello,TalkingCoder’,        msg2:’你好,TalkingCoder’},    methods:
{        sendData:function(){this.$refs.child1.$emit(‘set-data’,
{});this.$refs.child2.$emit(‘set-data’, {});        }    }})

透过$refs就可以给指定的零部件触发事件了,事实上,通过$refs是可以取获得子组件的任何实例的。

子组件派发事件,而父组件依旧使用了多少个相同子组件,如何区分是哪位组件派发的吧?或者地点的demo,比如我们的child组件$dispatch了一个自定义事件,可以如此来区分:

newVue({    data:
{        msg1:’Hello,TalkingCoder’,        msg2:’你好,TalkingCoder’},    methods:
{        sendData:function(){this.$refs.child1.$emit(‘set-data’,
{});this.$refs.child2.$emit(‘set-data’,
{});        },        handler1:function(){//
…},        handler2:function(){// …}    }})

像绑定DOM2事件一样,使用@xxx或v-bind:xxx来绑定自定义事件,来推行分裂的章程。

内容分发slot

有时大家编辑一个可复用的组件时,比如上面的一个confirm确认框:

题目、关闭按钮是联合的,可是中间正文的始末(包蕴样式)是想自定义的,那时候就会用到Vue组件的slot来散发内容。比如子组件的template的情节为:

提示

规定废除

父组件那样调用子组件:

欢迎来到TalkingCoder

说到底渲染完的内容为:

提示

欢迎来到TalkingCoder

确定废除

编辑可复用组件

此地引用一段出自vue.js文档的内容:

在编排组件时,记住是或不是要复用组件有利益。一次性组件跟其他组件紧密耦合没关系,然则可复用组件应当定义一个鲜明的当众接口。

Vue.js 组件 API 来自三有些——prop,事件和 slot:

prop同意外部环境传递数据给组件;

事件同意组件触发外部环境的 action;

slot同意外部环境插入内容到零部件的视图结构内。

利用v-bind和v-on的简写语法,模板的缩进清楚且精简:

Hello!

路由、组件和组件化

上文说了那么多,现在好不不难到重点了。在上一篇作品中,大家简要的涉及了组件化,那也是将Vue使用到极致的必经之路。我们先看一下src/main.js文件。

Vue有点像Express的用法,也有中间件的定义,比如我们用到的vue-router,还有vuex,它们都是vue的中间件,当然大家团结一心也可以支付基于vue的中间件。

importVuefrom’vue’;importVueRouterfrom’vue-router’;importAppfrom’components/app.vue’;importEnvfrom’./config/env’;Vue.use(VueRouter);//
开启debug方式Vue.config.debug =true;// 路由布置varrouter
=newVueRouter({    history: Env !=’production’});router.map({‘/index’:
{        name:’index’,       
component:function(resolve){require([‘./routers/index.vue’],
resolve);        }   
}});router.beforeEach(function(){window.scrollTo(0,0);});router.afterEach(function(transition){});router.redirect({‘*’:”/index”});router.start(App,’#app’);

如上代码就是main.js的始末,那也是我们项目跑起来后首先个执行的js文件。在导入了Vue和VueRouter模块后,使用Vue.use(VueRouter)安装路由模块。路由可以做一些大局配置,具体能够翻开文档,那里只说一个就是history,上文已经介绍了有关HTML5的History,它用history.pushState()和history.replaceState()来保管历史记录,服务器需求正确的布局,否则恐怕会404。开启后地址栏会像相似网站这样采取“/”来划分,比“#”要优雅很多,可以看出大家因此环境模块env.js默许给支付环境开启了History情势路由,生产条件没有打开,为的是可以让大家来体会到那二者的差别性,使用者可以自己来修改配置。

导入的app.vue模块就是大家的输入组件了,上篇小说已经介绍过,大家通过webpack生成的index.html里,body内唯有一个挂载节点

,当大家因而推行router.start(App,
‘#app’)后,app.vue组件就会挂载到#app内了,所以app.vue组件也是大家工程起来后,第三个被调用的组件,可以在它其中达成部分全局性的操作,比如获取登录新闻啊,总计日活啊等等。

在app.vue内,有一个的自定义组件,它就是整套网站的路由挂载节点了,切换路由时,它的情节会动态的切换,其实是在动态的切换分化的零部件,得益于webpack,路由间的切换可以是异步按需加载。

router.map()就是设置路由卓绝规则,比如访问127.0.0.1:8080/index,就会合作到”/index”,然后经过component,在回调里选择require()异步加载组件,这么些进程是足以改为联合的,不过相应没有人会如此做。vue-router协理匹配带参数的路由,比如’/user/:id’可以匹配到’/user/123’,或者’/user/*any/bar’可以匹配到’/user/a/b/bar’,:id是参数,*any是全匹配,但是vue-router援救的路由规则依然相比弱的,一般后端框架,比如Python的Tornado或者Node.js的Express是接济正则的。

vue的路由只是动态的调用组件,根本上仍旧MVVM,而Angular的路由是MVC的,在ng的controller里,可以运用templateURL来利用一个html片段,而vue的零件是不支持那种格局的,必须把html字符串写(或编译)在template里,因为在Vue的布署性里,一个组件(.vue文件)是应该把它的体制、html和js紧耦合的,那正是组件化的魅力所在。

嵌套路由。vue-router是辅助嵌套路由的,在app.vue里的是我们的根路由挂载,假诺急需,能够在某个具体的路由组件里面再使用一个来散发二级路由。具体使用办法可查阅文档。

路线跳转。vue-router使用v-link指令来跳转,它会隐式的在DOM上绑定点击事件:

首页首页

一经是在js里跳转,可以那样:

module.exports = {    data:function(){return{        }    },    methods:
{       
go:function(){console.log(this.$route);console.log(this.$router);this.$router.go(‘/index’); 
      }    }}

动用vue内置的$router方法也得以跳转,即使感兴趣,可以试试上面$route和$router打印出什么样内容,通过$route是足以得到当前路由的有些意况音信的,比如路径和参数。

vue-router还有一些钩子函数,通俗讲就是在发出三回路由时某个状态的一些回调。大家的花色main.js中使用了:

router.beforeEach(function(){window.scrollTo(0,0);});router.afterEach(function(transition){console.log(transition);});

beforeEach()是在路由切换起初时调用,那里大家将页面再次来到了上边。

afterEach()是在路由成功切换来激活状态时调用,可以打印出transition看看里面都有何。一般在此地能够做像自动导航、自动面包屑的局部大局工作。

router.redirect()很简单,就是重定向了,找不到路由时得以跳转到指定的路由。

小结

跟vue相关的组件化内容大约就是这样多了,说到底,vue的路由也是个零部件,与常常组件并不曾任何差别化,只是概念的例外。vue还有部分知识,比如自定义指令,自定义过滤器,这个规律也很接近,使用也很粗略,大家可以参考项目中的demo,结合文档来上学使用。在下一篇中,将介绍部分费用中沉淀的技巧或行使经验。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图