模板语法
vue使用的是基于HTML的模板语法,允许你以声明的方式将底层的vue实例数据绑定到用于渲染的DOM元素上。这意味着所有的vue模板都是可解析的有效的HTML。
在升级到2.0后,Vue将模板编译成虚拟DOM的渲染函数(类似Reactjs),但是 Vue 2.0 的实现有与众不同的地方。和 Vue 的响应式系统结合在一起之后,它可以让你不必做任何事就获得完全优化的重渲染。由于每个组件都会在渲染时追踪其响应依赖,所以系统精确地知道应该何时重渲染、应该重渲染哪些组件。不需要 shouldComponentUpdate,也不需要 immutable 数据 - it just works.
除此之外,Vue 2.0 从模板到 virtuel-DOM 的编译阶段使用了一些高阶优化:
-
它会检测出静态的 class 名和 attributes 这样它们在初始化渲染之后就永远都不会再被比对。
-
它会检测出最大静态子树 (就是不需要动态性的子树) 并且从渲染函数中萃取出来。这样在每次重渲染的时候,它就会直接重用完全相同的 virtual nodes 同时跳过比对。
这些高阶优化通常只会在使用 JSX 时通过 Babel plugin 来做,但是 Vue 2.0 即使在使用浏览器内的编译器时也能做到。
新的渲染系统同时允许你通过简单的冻结数据来禁用响应式转换,配以手动的强制更新,这意味着你对于重渲染的流程实际上有着完全的控制权。
以上这些技术组合在一起,确保了 Vue 2.0 在每一个场景下都能够拥有高性能的表现,同时把开发者的负担和成本降到了最低。
Templates, JSX, or Hyperscript?
开发者对于用模板还是 JSX 有很多的争执。一方面,模板更接近 HTML - 它能更好地反映你的 app 的语义结构,并且易于思考视觉上的设计、布局和样式。另一方面,模板作为一个 DSL 也有它的局限性 - 相比之下 JSX/hyperscript 的程序本质使得它们具有图灵完备的表达能力。
作为一个兼顾设计和开发的人,我喜欢用模板来写大部分的界面,但在某些情况下我也希望能拥有 JSX/hyperscript 的灵活性。举例来说,当你想在一个组件中程序化的处理其子元素时,基于模板的 slot 机制会显得比较有局限性。
那么,为什么不能同时拥有它们呢?在 Vue 2.0 中,你可以继续使用熟悉的模板语法,但当你觉得受限制的时候,你也可以直接写底层的 virtual-DOM 代码,只需用一个 render 函数替换掉 template 选项。你甚至可以直接在你的模板里使用一个特殊的<render>
标签来嵌入渲染函数!一个框架,两全其美。
以上是Vue作者的观点,我觉得Vue是具备包容性的,两种风格都照顾到了。
插值(Interpolations)
文本(text)
数据绑定最基础的形式是文本插值,使用 “Mustache” 语法("双大括号"看着像胡须):
<span>Message: {{ msg }}</span>
Mustache 标签会被相应数据对象的 msg 属性的值替换。每当这个属性变化时它也会更新。 你也可以只处理单次插值(vue2.0中使用v-once指令),今后的数据变化就不会再引起插值更新了,但请注意这会影响到该节点上所有的数据绑定:
<span v-once>This will never change: {{ msg }}</span>
原始的HTML(Raw HTML)
双 Mustache 标签将数据解析为纯文本而不是 HTML。为了输出真的 HTML 字符串,需要用到v-html指令:
<div v-html="rawHtml"></div>
被插入的内容都会被当做 HTML —— 数据绑定会被忽略。注意,你不能使用 v-html 来构成局部模板,因为 Vue 不是基于字符串的模板引擎。与之对应的,组件是作为 UI 重用和组成的基本单元的首选。
在网站上动态渲染任意 HTML 是非常危险的,因为容易导致 XSS 攻击。记住,只对可信内容使用 HTML 插值,永不用于用户提交的内容。
HTML属性
Vue2.0中Mustache 标签已经不能用在 HTML 属性 (Attributes) 内,取而代之的是v-bind指令(感觉好多的语法都被指令替代了- .-) :
<div v-bind:id="dynamicId"></div>
v-bind同样适用于布尔值的属性(比如控制按钮是否可用,他并不是单纯的绑定属性,而是在求值为False的时候动态移除该属性)
<button v-bind:disabled="someDynamicCondition">Button</button>
使用JS表达式
到目前为止,我们使用模板都只是绑定一些简单的属性键值。其实, Vue.js 在数据绑定上提供了完整的JavaScript 表达式支持:
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>
这些表达式将在所属的 Vue 实例的作用域内计算。不过也有个限制(正因为这个特性很强大,Vue作者并不建议在数据绑定中编写过于复杂的js逻辑,反而不易于维护,所以这个也是可以理解的),每个绑定只能包含单个表达式,因此下面的语句是无效的:
<!-- this is a statement, not an expression: -->
{{ var a = 1 }}
<!-- flow control won't work either, use ternary expressions -->
{{ if (ok) { return message } }}
模板表达式在沙盒中的运行的只能访问某些白名单中的全局变量,比如Date
Math
, 所以不要试图去访问用户自己定义的全局变量。
过滤器(Filters )
Vuejs允许自定义过滤器,用在一些常规的文本格式化工作上。过滤器需要跟在表达式后,用“管道符"标识:
{{ message | capitalize }}
注意管道语法不是 JavaScript 语法,因此不能在表达式内使用过滤器,只能添加到表达式的后面。 如果想在指令绑定中实现更复杂的行为,你应该用计算属性(在后面会提到)替代。
过滤器函数默认会接收表达式的值作为第一个参数。
new Vue({
// ...
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
})
过滤器也可以串联:
{{ message | filterA | filterB }}
由于过滤器同时也是函数,所以可以接受多个参数(比Vue1.x中用空格区分更直观了🍺):
{{ message | filterA('arg1', arg2) }}
这里得注意,arg1并不是作为第一个参数传进去,前面也提到了过滤器函数默认会接收表达式的值作为第一个参数,在管道符后指定的参数则会作为后者传入,也就是arg1其实是第二个参数,arg2则为第三个参数。
😇这篇太长了,有点晕了,模板语法还有点没写好,下篇继续~