@wy
2018-01-09T22:45:26.000000Z
字数 4599
阅读 664
Vue周末班
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架
接下里分别解读一下框架和库以及渐进式的理解
库,本质上是一些函数的集合。每次调用函数,实现一个特定的功能,接着把控制权交给使用者
框架,是一套完整的解决方案,使用框架的时候,需要把你的代码放到框架合适的地方,框架会在合适的时机调用你的代码
渐进式对应的英文为“Progressive”,意思是渐进的,一步一步,在一开始并不需要把所有的东西全都用上,而是根据项目的深入,逐步的用上合适的工具。
看下面作者给的图:
- 声明式的渲染(Declarative Rendering),DOM状态只是数据状态的一个映射,所有的逻辑尽可能在状态的层面去进行,当状态改变了,view会被框架自动更新到合理的状态
- 组件系统(Component System)将一个大型的界面切分成一个一个更小的可控单元
- 客户端路由(Client-Side Routing):当做单页应用时,需要管理路径和视图的映射关系,就需要路由解决方案
- 大规模的状态管理(Vuex),多个组件之间的共享、多个组件需要去改动同一份状态,需要集中式的管理应用的状体
- 构建工具(vue-cli),解决工程结构化,模块化,最终打包压缩部署测试的一系列流程的工具
参考文稿Vue作者尤雨溪:Vue 2.0,渐进式前端解决方案
响应式的数据绑定
当数据发生改变 -> 视图自动更新
可组合的视图组件
把视图按照功能,切分若干基本单元
组件可以一级一级组合成整个应用,形成了倒置的组件树
使用组件的好处:可维护、可重用、可测试
组件化应用构建
温馨提示:学习Vue要转换思路,忘记操作DOM这回事,而是专注于操作数据
那么接下来通过实例围绕着响应式的数据绑定来说一下第一个核心点。
// 引入vue.js文件
<script src="./src/vue.js"></script>
<body>
<!--Vue使用了基于HTML的模板语法,需要指定Vue管理的html模板范围,数据只能在此范围内解析-->
<div id="app">
<p>{{msg}}</p>
</div>
<script>
// 要展示的数据
let message = 'hello';
// 根实例 启动应用
// 传入一个对象作为参数,称之为选项对象,告诉vue做什么事情
let vm = new Vue({
el: '#app', // 需提供一个css选择器或者一个页面中已存在的DOM元素
// Vue实例的数据对象,用于提供给View提供数据
data:{
msg:message
}
})
</script>
</body>
可通过定时器来体验响应的数据绑定
以上代码省略....
setTimeout(function(){
vm.msg = '过了两秒,我改变了'
},2000)
或者打开浏览器的调试工具,在控制台输入
vm.msg = '改变我吧'
注意:Mustache 语法不能作用在 HTML 元素的属性上
<div id="app">
<p>{{msg}}</p>
{{ 1+1 }}
{{ true ? 1 : 2 }}
{{ [1,2,3].map(item => item*3) }}
</div>
<!-- !!!错误示范!!! -->
<h1 title="{{ err }}"></h1>
在以上例子中,定义的数据对象只是一个普通的对象,而修改它们时,视图会自动进行更新。
那么请带着一个疑问继续读下去:在改变属性的情况下,为什么能够让视图自动更新?
这就要说到Vue内部响应式的实现原理。
当在Vue实例的数据对象定义好数据后,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter,这一过程称之为数据劫持。并结合发布者-订阅者模式的方式,在数据变动时发布消息给订阅者,触发相应的监听回调。
基本用法:
// 普通的对象
var data = {value: 'hello'}
// 将value属性转为getter/setter访问器
Object.defineProperty(data,'value', {
// 获取值触发的函数
get () {return '这里填写属性对应的值'},
// 设置值触发的函数
set (newValue) {
// newValue 为设置的新值
console.log(newValue,oldValue);
}
})
data.value = 123; // 设置值
console.log(data.value); // 获取值
<input type="text" id="test" />
<div id="app"></div>
<script>
let test = document.querySelector('#test');
let app = document.querySelector('#app');
// 普通数据
var data = {
message: 'hello'
}
observe(data)
// 劫持数据的方法
function observe(data){
Object.keys(data).forEach((key) => {
defineReactive(data,key,data[key])
})
}
// 转成getter和setter的形式
function defineReactive(data,key,val){
Object.defineProperty(data,key, {
get () {
return val
},
set (newValue) {
val = newValue;
// 设置值时自动更新视图
app.innerHTML = val;
}
})
}
// 将数据绑定到视图
app.innerHTML = data.message;
test.value = data.message;
// 给交互的元素绑定input事件,改变数据
test.addEventListener('input',function (){
// 改变数据后会自动更新视图
data.message = this.value;
// 不需要手动更新啦
/*
app.innerHTML = data.message;
test.value = data.message;
*/
})
</script>
MVVM(Model–view–viewmodel)是一种软件架构模式,更好的UI模式解决方案。
主要有三个部分组成:
- M: Model 数据模型
- V:View 视图(对于前端来说,就是页面)
- VM:ViewModel 视图模型
MVVM通过数据双向绑定让数据自动地双向同步,数据到视图的更新,和视图改变更新数据,它的核心是数据,不推荐开发人员手动操作DOM,将精力主要放在操作数据上。Vue也借鉴了这种模式。
可以通过一张图感受一下:
那么在上面的例子中,分解来说:
- html模板就是view模型
- data数据对象就是计划好的数据模型model
- new Vue()就是view-model模型
通过上面对响应的数据原理分析,我们知道Vue内部会将普通对象劫持,依次会把属性转为 getter/setter访问器,从而达到响应的目的。
那么这里有一个细节要注意,Vue劫持的是在数据对象中已经计划好的数据,也就是一开始就定义在数据对象中的属性,如果在初始化实例时一些属性没有定义,而在未来才将属性添加到对象,由于 JavaScript 的限制,Vue不能检测到对象属性的添加或删除,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 现在是响应式的
vm.b = 2
// `vm.b` 不是响应式的
注意:以上代码只能辅助理解那些是响应的属性,那些不是响应的属性,而不能将
b这个属性渲染在页面中,否则会报错。
<!--未在数据对象中声明的数据,直接在这里使用会报错-->
<p>{{b}}</p>
但是,我们可以定义一个对象,在模板中获取对象的属性。这样来测试
<div id="app">
{{msg}}
{{list.ok}}
<!--在实例初始化时,bad属性并未定义,所以页面无任何输出-->
{{list.bad}}
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: 'hello',
list: {
ok: 'ok reactive'
}
}
})
// 给list添加属性不是响应的,所以页面依然不能显示bad数据
vm.list.bad = '我是新添加的'
</script>
以上的msg、list对象、ok属性都是计划好的,所以会被劫持转成getter和stter,而bad属性是之后才添加的,所以不能响应在页面中。