前言
公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子。后来接到一个基于模板的活动设计系统的需求,便有了下面的内容。借油开车。
组件化
需求一到,接就是怎么实现,技术选型自然成为了第一个问题。鉴于目前web前端mvvm框架以及组件化开发方式的流行,决定技术栈采用:vue + es6 + 组件化。
这里首先简单说下web前端组件化开发方式的历程:
最早的组件化结构,代码结构可能如下:
- lib/components/calendar |- calendar.css |- calendar.js |- calendar.html</div>
将同功能的组件文件放到同一目录下,结构清晰、职责明确,视图、样式、脚本的关系显著,也易于单元测试,是独立展示和交互的最小单元。
后来:
在之前基础上对组件进行了生命周期的加工(初始化、获取资源、渲染、更新、销毁等),理顺了组件的各个阶段,有助于对组件实现(从初始化到销毁)的理解。并且借助于组件各个阶段的钩子可以对组件有更好的利用和扩展。对外暴露接口,数据绑定或者说数据仓库的加入,各种xMD模块加载器的出现,也让这种这种开发方式上升了一个层级。ExtJs、YUI等都是这方面的专家。
再后来:
有了之前发展,进步是很大的,但依然不够。组件的可复用性(基础样式,基础逻辑,基础属性、可复用的稳定业务逻辑等)、组件间通信、全局状态管理、甚至是能否有更好的代码组织方式等依然是问题。Angular、React、Polymer、Vue等mvvm框架和webpack、browserify等构建、预编译工具的出现正试图解决这些问题。
ES6
在正式开始vue之前,因为本项目用到了es6,那么就谈谈大家都关注的EcmaScript6。多余的就不说了,es6经历了多年的苦,终于在2015年下半年定稿,正式名称:EcmaScript2015。每个刚开始接触es6的人应该都有这么一个问题,es6的出现到底是为了什么,或者说它解决了什么。老版本es4/5虽然坑多,就像Brendan Eich评价js一样:"优秀之处并非原创,原创之处并不优秀"。但我们不也是去其槽粕,留其精髓,一路填坑走过了吗?
来直接一点,es6常用的特性有:class类的支持、箭头函数、对象和数组的解构、默认参数、不定参数、对象合并、let与const关键字、for of迭代、字符串模板、对象字面量增强、同名对象字面量缩写、模块化import/export、map、promise、* yeild生成器等。
这里挑出几个常用的简单说下:
首先class:
在没有class的时候,创建类的一种比较标准的方式是将非函数的属性放到构造函数里,函数属性在原型链里添加。类的继承的实现就更为多样:对象冒充、call/apply方式、原型链方式等。es6的class和extends关键字的出现给出了一个统一的规范
class People { constructor (name, age, gender){ this.name = name } sayName (){ return this.name } } class Student extends People { constructor (name, age, gender, skill){ super(name, age, gender) this.skill = skill } saySkill (){ return this.skill } } let tom = new Student('tom', 16, 'male', 'computer') tom.sayName() // => 'tom' tom.saySkill() // => 'computer' tom.__proto__ == Student.prototype // => true Student.__proto__ == People // => true</div>
可以看出虽然是新的规范,但是还是遵守js的原则:对象的__proto__指向它的构造函数(类)的prototype。es6对象字面量的__proto__注入也能快速的实现继承。
接下来是let:
es6之前js只有函数作用域,let的出现有了块级作用域,也就算是if、else、for这类也有了作用域,块内用let声明的变量外面是访问不到的,在js预解析的时候,是不会被提升到当前函数作用域的前面的。基于该特性,在for迭代的时候,每次迭代都会产生一个块级作用域的独立的迭代变量,让最后的结果就是我们期待的结果。
var arr = []; for (let i = 0; i < 10; i ++){ arr[i] = function (){ return i } } arr[6]() // => 6 //如果用var声明i,无论多少次迭代,外层的i始终被每次迭代的函数内部引用着(闭包),不会被当做垃圾回收,最后的结果都指向同一个i,值为10。 //以往为了避免这个问题,通常会这么做: for (var i = 0; i < 10; i ++){ arr[i] = (function (i){ return function (){ return i } })(i) }</div>
最后讲讲箭头函数:
es6之前的function有一个特点:函数内部的上下文并不是由该函数写在那里决定的,而是由谁调用决定的,谁调用函数内部的this就指向谁。然后我们有些时候并不想让他这样,但又没办法,只能通过先保存this,或者call/apply,或者bind来调整上下文。箭头函数的出现解决了这个宁人苦恼的问题,因为箭头函数内的上线文(this)是由函数写在哪决定的,无论被哪个对象调用,上下文都不会改变。
var obj = { test1 : function (){ window.setTimeout(function (){ console.info(this) }, 100) }, test2 : function (){ window.setTimeout(() => { console.info(this) }, 100) } } obj.test1() // => Window obj.test2() // => obj</div>
用普通函数还是箭头函数并非绝对,箭头函数也不能完全替代普通函数,要用哪个由具体逻辑决定,前提是要先了解他们的区别。
箭头函数还有一个特点就是能够简化return的书写。
var a = function (n){ return n } var b = (n) => n //可以省略return和花括号 var c = n => n //如果只有一个参数,中括号也可以省略 a(1) // => 1 b(1) // => 1 c(1) // => 1</div>
从这几个简单的例子可以看出,es6不仅仅是新增了几颗糖,对之前js的一些不友好的地方的改善才是重点。
Vue
进入正题,
Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据驱动的 web 界面的库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。
Vue.js 自身不是一个全能框架——它只聚焦于视图层。因此它非常容易学习,非常容易与其它库或已有项目整合。另一方面,在与相关工具和支持库一起使用时,Vue.js 也能完美地驱动复杂的单页应用。
— 文中关于vue的大部分内容引用自vue的官方文档,感谢作者的工作!
响应的数据绑定:
<div id="app"> <p>{{ message }}</p> <input v-model="message"> </div> new Vue({ el : '#app', data : { message : 'Hello Vue.js!' } })</div>
结果:改变输入框的值,<p>标签的文本也会对应改变。
基本工作原理:<input>输入框的值与vue实例的message属性进行了绑定,<p>标签的文本也与message属性进行了绑定。输入框值的变化会改变message的值,message值的变化会反应到<p>标签的文本上。
Vue.js 的核心是一个响应的数据绑定系统,它让数据与 DOM 保持同步非常简单。在使用 jQuery 手工操作 DOM 时,我们的代码常常是命令式的、重复的与易错的。Vue.js 拥抱数据驱动的视图概念。通俗地讲,它意味着我们在普通 HTML 模板中使用特殊的语法将 DOM “绑定”到底层数据。一旦创建了绑定,DOM 将与数据保持同步。每当修改了数据,DOM 便相应地更新。这样我们应用中的逻辑就几乎都是直接修改数据了,不必与 DOM 更新搅在一起。这让我们的代码更容易撰写、理解与维护。
组件系统:
组件系统是 Vue.js 另一个重要概念,因为它提供了一种抽象,让我们可以用独立可复用的小组件来构建大型应用。如果我们考虑到这点,几乎任意类型的应用的界面都可以抽象为一个组件树:
实际上,一个典型的用 Vue.js 构建的大型应用将形成一个组件树。
你可能已经注意到 Vue.js 组件非常类似于自定义元素——它是 Web 组件规范的一部分。实际上 Vue.js 的组件语法参考了该规范。例如 Vue 组件实现了 Slot API 与 is 特性。但是,有几个关键的不同:
Web 组件规范仍然远未完成,并且没有浏览器实现。相比之下,Vue.js 组件不需要任何补丁,并且在所有支持的浏览器(IE9 及更高版本)之下表现一致。必要时,Vue.js 组件也可以放在原生自定义元素之内。
Vue.js 组件提供了原生自定义元素所不具备的一些重要功能,比如组件间的数据流,自定义事件系统,以及动态的、带特效的组件替换。
组件系统是用 Vue.js 构建大型应用的基础。另外,Vue.js 生态系统也提供了高级工具与多种支持库,它们和 Vue.js 一起构成了一个更加“框架”性的系统。
这里简单介绍下vue最常用也较重要的两块:响应式原理和组件系统。