新增:哈哈,最近又推出了 vue 的文章,在这里放个连接~
手把手教你从零写一个简单的 VUEjavascript
感谢有人看我扯技术,这篇文章主要介绍最近很是火的vue2前端框架的特色和vue2+vuex2+webpack2各类2的先后端同构渲染架构搭建流程,最后会附上代码,文章想到啥写啥,若是存在错误,或者你们有什么意见建议,欢迎你们指出来css
vue2出来以后,基本上逛论坛逛技术群都能看到各类文章,各类讨论 ,一时间你们都在学习vue2了 ,我今年年初就开始接触vue,最初也是在react ,angular,vue 之中对比选择,最终选择了vue,由于其对前端比较友好(使用正常的模板,而不是JSX)、概念及学习成本相对简单(对于团队开发,引入技术必需要考虑其学习成本),下面介绍下我理解的vue2和vue1的不一样之处 ,若有不足,欢迎补充:html
1.引入了virtual Dom
前端
在vue1中,数据和视图的绑定流程是经过
Object.defineProperty
将数据转化为getter/setter
,getter/setter
中加入watcher
,当对数据进行操做的时候,setter
的watch
被触发从新计算,而后更新和这个数据有关联的dom元素,这就是vue1的数据驱动视图原理
在vue2中,数据的绑定和触发和vue1相同,基本原理都是经过Object.defineProperty
对数据加入'钩子',以便在数据发生变化的时候得以响应,而在响应以后,不像vue1同样直接更新dom元素,而是放入virtual Dom
中,进行比对计算,而后对dom元素作相应的处理。下面是vue1和vue2的响应流程对比vuevue:
java
vue2:
node
关于
virtual Dom
: 虚拟dom最初是在react上面认识的,其实作的事情就是在js内存中创建好dom的结构,而后再更新虚拟dom时作差别比对,将差别的地方真正更新到页面中,作到最小化页面的渲染。固然,也不是说对于全部情景,虚拟dom的性能都是最好的,毕竟比起直接操做dom元素,他仍是须要在内存中进行计算,所以对于少许的元素更新,可能其性能比起直接操做dom元素要差。固然虚拟dom的引入,不仅是在性能方面的考虑,虚拟dom能够带来编程的变化,好比你可使用render
方法直接建立新的节点,虚拟dom也是vue2能够进行服务端渲染的关键,因为虚拟dom是在内存重点,vue2的ssr能够将虚拟dom直接生成html的字符串,从而实现ssr。除此以外,vue2 从模板到 virtuel-DOM 的编译阶段使用了一些高阶优化:react(1). 它会检测出静态的
class
名和attributes
这样它们在初始化渲染以后就永远都不会再被比对。
(2). 它会检测出最大静态子树 (就是不须要动态性的子树) 而且从渲染函数中萃取出来。这样在每次重渲染的时候,它就会直接重用彻底相同的virtual nodes
同时跳过比对。
这些高阶优化一般只会在使用JSX
时经过Babel plugin
来作,可是 vue2 即便在使用浏览器内的编译器时也能作到。webpack
2.组件事件传递机制的改变,组件数据双向绑定的去除git
vue2组件废除了
$dispath/$broadcast
父子组件的事件传播方式,废除了过滤器,props
参数等的数据双向绑定以及处理功能,说明做者但愿使用者经过创建全局的状态管理,事件管理机制,经过使用事件中心,容许组件自由交流,不管组件处于组件树的哪一层,将状态管理集中在一块儿处理,官方提供的vuex
就是用来几种管理状态的。
3.服务端渲染 ssr:server-side-render
因为
virtual dom
的引入,使得vue的服务端渲染成为了可能,下面是官方vue-server-renderer
提供的渲染流程图:能够看出vue的
server-side-render
有三部分组成,一部分是页面的源码(source),还有node层的渲染部分和浏览器端的渲染部分。
source
分为两种entry point
,一个是前端页面的入口client entry
,主要是实例化Vue对象,将其挂载到页面中;另一个是后端渲染服务入口server entry
,主要是控服务端渲染模块回调,返回一个Promise对象,最终返回一个Vue对象(通过测试,直接返回Vue对象也是能够的);前面的
source
部分就是业务开发的代码,开发完成以后经过webpack
进行构建,生成对应的bundle,这里再也不赘述client bundle
,就是一个可在浏览器端执行的打包文件;这里说下server bundle
, vue2提供vue-server-renderer
模块,模块能够提供两种render:rendererer/bundleRenderer
,下面分别介绍下这两种render。
renderer
接收一个vue对象 ,而后进行渲染,这种对于简单的vue对象,能够这么去作,可是对于复杂的项目,若是使用这种直接require一个vue对象,这个对于服务端代码的结构和逻辑都不太友好,首先模块的状态会一直延续在每一个请求渲染请求,咱们须要去管理和避免此次渲染请求的状态影响到后面的请求,所以vue-server-renderer
提供了另一种渲染模式,经过一个bundleRenderer
去作渲染。
bundleRenderer
是较为复杂项目进行服务端渲染官方推荐的方式,经过webpack以server entry
按照必定的要求打包生成一个server-bundle
,它至关于一个能够给服务端用的app的打包压缩文件,每一次调用都会从新初始化 vue对象,保证了每次请求都是独立的,对于开发者来讲,只须要专一于当前业务就能够,不用为服务端渲染开发更多的逻辑代码。
renderer生成完成以后,都存在两个接口,分别是renderToString
和renderToStream
,一个是一次性将页面渲染成字符串文件,另一个是流式渲染,适用于支持流的web服务器,能够是请求服务的速度更快
4.除了上面说的那些不一样,vue2在生命周期管理,动画机制等地方都与vue有些差异,具体请浏览migration
相对于 vue2和vue 较大改动,vue的状态管理工具 vuex的改动不是很大,底层改动因为时间关系尚未来得及细究,可是在使用方面多了几个 Helper,利用ES6的展开函数能够更加方便的使用
state,getters,mutations,actions
。下面简单介绍下vuex各个部分的概念
state
是一个全局的状态存储,数据会存储在其中,vue组件能够直接访问其中的值,可是只能够读,不能够进行写操做getter
,有些时候咱们须要对获取的数据进行加工,而不是直接获取state中的数据,这时候能够经过getter定义函数,返回对应的数据mutations
是vuex中惟一一个能够修改数据的地方,mutations
能够定义事件函数,在vue组件中能够经过commit发射事件,调用函数。须要注意的是,mutations
中的操做必须是同步的,不能够存在异步操做的状况。actions
和mutation
比较类似,不一样的是actions中不直接修改state,而是经过commit调用mutations修改数据,并且actions中能够存在异步处理逻辑
webpack2
和webpack
对比,有如下的新特性:
- ES6 Modules : webpack 2 已经支持原生的 ES6 的模块加载器了,这意味着 webpack 2 可以理解和处理 import和export了,而不用把他们转化成 CommonJS 来处理了。
- 用 ES6 来作代码拆分 : ES6 的模块加载器定义了System.import这一个方法,System.import可以在运行时动态加载 ES6 模块。
- 混合使用 ES6 和 AMD 和 CommonJS (Mixing ES6 with AMD and CommonJS)
更加具体的新特性能够浏览连接地址
好了,前面扯了那么多东西,估计没什么人看,咱们仍是回归题目,开始敲代码吧,哈哈,接下来我会使用vue2 + vuex2 + webpack2 搭建一个简单的 ssr项目,可以直出页面,还可以保存成静态文件。虽然官方页面响应的实例vue-hackernews-2.0,可是若是一开始把代码下下来,仍是不太容易理解的,因此我参考其例子,从零开始搭建项目,源码在文章的最后
首先固然是使用
npm init
新建一个项目
而后往package.json
中写入下列依赖
而后运行
npm i
,而后去上个厕所,喝杯茶也行,等全部的依赖安装完毕
介绍下一些模块的做用vue,vuex
为vue项目使用的基本框架,express,vue-server-renderer,serialize-javascript
为服务端渲染使用的模块,babel-*
为ES6转换成ES5模块,其余的webpack*,*-loader
为webpack构建所须要的模块,若是须要项目学习webpack的使用,能够阅读官方文档安装阶段完成了,下面进入愉快的编码阶段了,其实按照流程应该是编码同时搞定打包、开发环境配置等工做的,为了文章的效果,就分开说了
制做的页面是一个没有什么业务情景的页面(请原谅我,想到什么就写什么代码了),主要是为了演示组件的引用流程,vuex状态管理以及引用,状态改变以后的视图更新,异步操做的视图更新,因此,当你下了源码,大概页面,你会看到下面这个奇奇怪怪的东西:
好了不要在乎这些细节了,咱们来看看这个怪怪的东西是怎么出来的,先展现下项目最终的目录结构:
其中
index.html
就是页面最终生成页的模板页,里面有简单的头部信息和占位符,能够在服务端渲染后进行内容替换app.js
就是页面的逻辑入口文件,Vue对象在这里实例化,其中使用的store,route能够在实例化中传入能够看到
app.js
引用了App.vue
组件,.vue
是vue官方推出的单文件开发方式,配合webpack的vue-loader
能够方便的实现模块化开发,.vue
文件在打包的时候会被编译成为一个js对象,里面包含一个render
方法,用于渲染页面,下面是App.vue
文件
能够看到页面包含三个部分
template 、script 、style
,其中template为组件使用的模板,如今vue2除了使用template,还可使用JSX和js模板,可是相对其余两种,template对于前端开发者来讲仍是比较直观的,script为组件的逻辑部分,使用es6的进行模块化,构建的时候会使用Vue.extend生成一个组件,style为页面的样式部分,能够指定lang
来声明使用的样式语法类型,能够用原生的css,也能够用stylus,sass等等,只要配置不一样的webpack loader进行进行编译就好了,另外能够指定scoped
,使得组件中的样式只对组件生效,不会影响其余组件,不用担忧命名重复的问题,其原理是在生成的时候为标签生成一段随机数(没研究过生成数的算法),而且为选择器加上对应随机数的属性选择器。能够看到组件
import
另一个List.vue
组件,而且在components
中进行了引用,template
中进行了引用,这就实现了组件的嵌套和复用,下面是List.vue
文件
这个文件使用了vuex管理的数据,在此前的版本的vuex中,在组件使用数据须要写不少的
computed,methods
,在新版本的能够配合ES6的展开函数和vuex的helper,简写不少函数,组件部份内容就说到这里了,可能有人会说啥是computed,啥是methods,这些统统本身看文档,
总的来讲,写一个组件须要了解下面几点:
- 模板指令,例如
v-for,v-bind,v-on
等- 数据使用配置属性
data,computed,props,watch
等- 组件的生命周期属性
created,mounted
等- 全局方法
Vue.set,Vue.nextTick
等- 进阶开发: 动画效果,自定义指令,自定义插件,混合组件开发
下面说下用vuex作状态管理,下面是
store/index.js
文件
能够看到使用vuex须要在
Vue.use
中引入,而后实例化一个Vuex.Store
对象就能够了,对象中须要定义state,actions,mutations,getters
等内容,这样子就能够创建一个全局的状态管理机制,能够从应用的顶端去处理数据,各个组件中对数据进行操做也是经过事件直接传递到Vuex中进行数据更新,而后再进行响应到其余使用同个数据的组件中,进行视图更新。项目的逻辑代码已经完成了,可是对照上面ssr的概念,会发现还少了两个webpack的
entry point
,一个是前端代码的入口,能够是供服务端渲染的入口,下面是前端client-entry.js
文件
文件引入了
app.js
,判断若是在服务端渲染时已经写入状态,则将vuex的状态进行替换,使得服务端渲染的html和vuex管理的数据是同步的。而后将vue实例挂载到html指定的节点中。下面是
server-entry.js
文件这里面服务端会传过来一个context对象,能够从获取信息,也能够写入信息,能够看到将现有的vuex state赋值给context,给服务端渲染使用,最后返回vue对象(文档中写着须要返回一个Promise对象,对象中再返回一个vue对象,通过实验直接返回也是能够的,若是应用中存在异步操做会影响视图和vuex数据状态,那么应该返回一个Promise对象,使得服务端获得的vue对象是最后数据和视图同步统一的)
代码撸完了,下面要让他跑起来了,配置分为两部分,一个是webpack打包的配置,一个是服务端渲染服务器的搭建,这里使用express进行服务器的简单搭建,不涉及任何负载均衡和性能优化问题,下面分别说说这两个部分 :
- webpack打包:webpack打包主要有三个文件
webpack.base.config.js
,webpack.client.config.js
,webpack.server.cofnig.js
,其中base
主要配置了对应文件类型的loader,还有指定了entry的切割点,将业务代码和库,client
指定了client-entry.js
做为entry point ,还将库文件和业务文件进行分别打包,还有一些图片处理,代码压缩的工做。server
指定了server-entry.js
做为entry point,而且指定了打包了类型标准是commonjs2
,供服务端渲染模块使用。- 而在开发过程当中,可使用
webpack-hot-middleware/client
,webpack-hot-middleware
去实现代码的watch和从新构建双端的代码的流程,是得开发更加便捷,具体配置在setup-dev-server.js
中- 最后说一下服务端渲染的服务器配置,服务端部分使用
vue-server-renderer
模块的createBundleRenderer
经过传入刚才webpack生成的server-bundler
去生成一个bundleRenderer
,就能够调用renderToStream
或者renderToString
渲染页面了,具体配置在server.js
中具体怎么跑起项目能够看下
package.json
的scripts属性,其中dev
是开发用,start
是正式环境动态生成页面用,build
能够直接生成client-bundler
和server-bundler
基本上比较完整的vue2 前段端同构渲染已经介绍完了,下面说下我对框架的见解,前端框架这个东西基本上就是一时火一个,咱们在学习新东西的同时也应该不忘老本,要有本身的技术栈和工做流,就像《人月神话》中的一句话说的好,没有解决任何事情的银弹,对于不一样的项目,不一样的业务情景,应该采起不一样的框架,使用最合适的开发架构去开发。
附上代码 点我点我,给个star呗~
最后也没啥好说的了,要不给你们拜个早年吧,祝你们代码没bug,哈哈