介绍与Vue.j s 有关的一些概念、技术、原理。并快速构建出一个Vue.js 应用。
Vue.js
(读音 /vjuː/,类似于view
) 是一套用于构建用户界面的渐进式(Progressive
)框架。与其它大型框架不同的是,Vue
被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
简单小巧的核心,渐进式技术栈,足以应付任何规模的应用。简单小巧是指Vue.js
压缩后大小仅有17KB。所谓渐进式,就是您可以(step by step
)一步一步、有阶段性地来使用Vue .j s ,不必一开始就使用所有的东西。
使用Vue.js
可以让Web
开发变得简单,它提供了现代Web
开发中常见的高级功能:
假设您已了解关于 HTML、CSS 和 JavaScript 的中级水平的知识,就可以开始学习了。如果您刚开始学习前端开发,将框架作为你的第一步可能不是最好的主意——掌握好基础知识再来吧!
① 兼容性:
Vue 不支持 IE8 及以下版本,因为 Vue 使用了 IE8 无法模拟的 ECMAScript 5 特性。但它支持所有兼容 ECMAScript 5 的浏览器。
② 直接用 <script>
引入:
直接下载并用 <script>
标签引入,Vue
会被注册为一个全局变量。
对于制作原型或学习,可以这样使用最新版本:
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
对于生产环境,推荐链接到一个明确的版本号和构建文件,以避免新版本造成的不可预期的破坏:
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
如果使用原生 ES Modules,这里也有一个兼容 ES Module 的构建文件:
<script type="module">
import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.esm.browser.js '
</script>
可以在 cdn.jsdelivr.net/npm/vue 浏览 NPM 包的源代码。
Vue 也可以在 unpkg 和 cdnjs 上获取 (cdnjs 的版本更新可能略滞后)。
请确认了解不同构建版本并在你发布的站点中使用生产环境版本,把 vue.js 换成 vue.min.js。这是一个更小的构建,可以带来比开发环境下更快的速度体验。
③ NPM
在用 Vue
构建大型应用时推荐使用 NPM 安装。NPM
能很好地和诸如 webpack 或 Browserify 模块打包器配合使用。同时 Vue
也提供配套工具来开发单文件组件 。
$ npm install vue # 最新稳定版
④ 命令行工具 (CLI)
Vue
提供了一个官方的 CLI,为单页面应用 (SPA
) 快速搭建繁杂的脚手架。它为现代前端工作流提供了 开箱即用
(batteries-included) 的构建设置。只需要几分钟的时间就可以运行起来并带有热重载、保存时 lint
校验,以及生产环境可用的构建版本。更多详情可查阅 Vue CLI 的文档。
Vue CLI
是用于快速Vue.js
开发的完整系统,它提供:
@vue/cli
实现;@vue/cli + @vue/cli-service-global
实现;@vue/cli-service
实现,这个是:可升级;建立在webpack之上,具有合理的默认值;可通过项目内配置文件进行配置;Vue CLI
的目标是成为Vue
生态系统的标准工具基线。 它可以确保各种构建工具与合理的默认设置一起顺利运行,因此可以专注于编写应用程序,而不必花费大量时间进行配置。 同时,它仍然可以灵活地调整每个工具的配置,而无需弹出。
Vue CLI
有几个移动的部分,其中包含许多单独发布的软件包。
CLI
CLI
(@vue/cli
)是全局安装的npm软件包,并在终端中提供vue
命令。 它提供了通过vue create
快速搭建新项目的能力,或通过vue serve
立即为新创意制作原型的功能。 还可以通过vue ui
使用图形用户界面来管理项目。
安装:
npm install -g @vue/cli
创建一个项目:
vue create mypro
# 或
vue ui
CLI Service
CLI Service
(@vue/cli-service
)是开发依赖项。 这是一个安装在本地的由@vue/cli
创建的每个项目中的npm
软件包。CLI Service
基于webpack和webpack-dev-server构建。
CLI Plugins
CLI Plugins
是npm软件包,可为Vue CLI项目提供可选功能,例如Babel / TypeScript编译,ESLint集成,单元测试和端到端测试。
Vue.js
在设计上使用MVVM
模式 , MVVM是Model-View-ViewModel的简写,即模型-视图-视图模型。【模型】指的是后端传递来的数据;【视图】指的是所展示的页面;【视图模型】为MVVM
模式的核心,它是连接View和Model的桥梁。它有两个方向:一是将【模型】转化成【视图】,即将后端传递的数据转化成所展示的页面。实现的方式是:数据绑定
。二是将【视图】转化成【模型】,即将所展示的页面转化成后端需要的数据。实现的方式是:DOM 事件监听。这两个方向所实现的即为数据的双向绑定。
在MVVM
的模式下View
和Model
是不能直接通信的,它们通过ViewModel
来通信。ViewModel通常要实现一个observer
观察者,当Model
数据发生变化,ViewModel
能够监听到数据的这种变化,然后通知到对应的View
做自动更新。而当用户操作View
,ViewModel也能监听到View
的变化,然后通知Model
做数据改动,这实际上就实现了数据的双向绑定。
MVVM
模式是由经典的软件架构MVC
衍生来的。当View
(视图层)变化时,会由ViewModel
(视图模型)监听到并自动更新到Model
(模型),反之亦然。View
与ViewModel
和 ViewModel
与Model
之间通过双向绑定(data-binding )建立联系。如图1所示:
图 1. M V V M关系
Vue
就是基于MVVM模式实现的一套框架。在Vue中,Model
指的是JavaScript中的数据
,如对象、数组
等等;View
指的是页面视图
;ViewModel
指的是Vue的实例化对象
。
Vue.js操作DOM:
① 在清单1中实现ES5操作DOM
清单 1. ECMAScript 5操作DOM
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ES5操作DOM</title>
</head>
<body>
<div id="app"></div>
<script>
var app = document.getElementById("app")
var showBtn = true;
function handleButtonClick() {
if(showBtn) {
console.log('已点击了我!')
var hone = document.createElement("h1");
hone.innerHTML = '已点击了我!';
app.appendChild(hone);
showBtn = false;
}
}
var btn = document.createElement("button");
btn.innerHTML = "点击我";
btn.onclick = handleButtonClick;
app.appendChild(btn);
</script>
</body>
</html>
清单1中这段代码不难理解,操作的内容也不复杂,不过这样让我们的视图代码和业务逻辑紧藕合在一起,随着功能不断增加,直接操作DOM 会使得代码越来越难以维护。
② 在清单2中实现Vue.js操作DOM
Vue.js 通过MVVM 的模式拆分为视图
与数据
两部分,并将其分离。因此,只要关注数据
即可, DOM的事情Vue 会自动搞定。上面的示例清单1用Vue.js 可以改写为清单2:
清单 2. Vue.js操作DOM
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Vue操作DOM</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<button v-if="showBtn" v-on:click="handleClick">点击我</button>
<h1>{{clickme}}</h1>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
showBtn: true,
clickme:''
},
methods: {
handleClick: function() {
console.log('已点击了我!');
this.clickme = '已点击了我';
}
}
})
</script>
</body>
</html>
清单 2中的代码,当执行 new Vue() 时,Vue 就进入了初始化阶段,一方面,Vue 会遍历 data 选项中的属性,Observer
数据监听器,把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用Object.defineProperty()方法把这些属性全部转成setter、getter方法。当data中对象的某个属性被访问时,则会调用getter方法,当data中对象的属性被改变时,则会调用setter方法。实现数据变化监听功能;另一方面,Vue 的指令编译器Compile
对元素节点的指令进行解析,替换模板数据,初始化视图。并使得订阅者Watcher
绑定对应的更新函数Updater
以更新视图。 此时Watcher
会将自己添加到消息订阅器中(Dep
),初始化完毕。
当数据发生变化时,Observer
中的 setter 方法被触发,setter 会立即调用Dep.notify()
,Dep 开始遍历所有的订阅者,并调用订阅者的 update
方法,订阅者收到通知后对视图进行相应的更新。
其中的el
用于外部的模板template
或者将HTML作为模板编译。用于指定一个页面中己存在的DOM 元素来挂载Vue实例。
图 2. Vue执行流程
如今的前端开发己不再是写个HTML 和css 那样简单了,新的概念不断涌现,已有像ECMAScript 6
、Node.js
、NPM
、前端工程化
等。它们正在不断优化现有的开发模式,改变传统的编程思想。
曾经以jQuery框架技术为核心的技术栈被许多商业项目用于生产环境:
jQuery + RequireJS ( SeaJS ) + artTemplate ( doT ) + Gulp ( Grunt)
这套技术栈能兼容绝大部分浏览器,有的的客户很可能还在用IE 8
及以下浏览器;使用RequireJS 或SeaJS 进行模块化开发可以解决代码依赖混乱的问题,同时便于维护及团队协作;使用轻量级的前端模板(如doT )可以将数据与HTML模板分离;最后,使用自动化构建工具(如Gulp )可以合并压缩代码,如果采用写Less
、Sass
以及现在流行的ES 6
,也可以进行预编译。
由于以jQuery框架技术为核心的技术栈的简单、高效、实用, 至今仍有不少开发者在使用,这样一套前端解决方案就称为传统前端开发模式
。其核心是直接操作DOM的思想,jQuery是使用选择器($
)选取DOM对象,对其进行赋值、取值、事件绑定等操作,其实和原生的HTML的区别只在于可以更方便的选取和操作DOM对象,而数据和界面是在一起的。
不过随着项目的扩大和时间的推移,出现了更复杂的业务场景,比如SPA (单页面富应用〉、组件解耦等。为了提升开发效率,降低维护成本,传统的前端开发模式己不能完全满足项目的需求,这时就出现了如Vue.js
、Angular
、React
等框架技术为代表的现代Web前端开发模式
。
Vue.js
是一个渐进式的JavaScript框架,根据项目需求,可选择从不同的维度来使用之。如果开发简单的HTML5页面应用,可以通过<script>
直接加载Vue.js
独立文件,并不需要jQuery
等另外的库文件 :
<!--自动识别最新稳定版本的Vue.j s -->
<script src = "https://unpkg.com/vue/dist/vue.min.js"></script>
<!--指定某个具体版本的Vue.j s -->
<script src = "https://unpkg.com/vue@2.6.11/dist/vue.min.js"></script>
引入Vue.js
框架后,在页面元素标记<body>
的底部使用new Vue()
的方式创建一个实例,其表示的是ViewModel
,它将数据Model
和界面视图View
完全分离开来了,对数据进行操作不再需要引用相应的DOM对象,可以说数据和视图是分离的,他们通过Vue对象
实现相互的绑定。这就是Vue.js
最基本的开发模式,即MVVM模式
。清单2中给出Vue
实现完整代码,而清单3给出jQuery
实现完整代码:
清单 2. Vue 示例:用户列表展示
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Vue 示例:展示用户列表</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="u in users">{{u.name}}</li>
</ul>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
users: [
{name : '张三' },
{name : '李四' },
{name : '王麻子' }
]
}
})
</script>
</body>
</html>
清单 3. jQuery 示例:用户列表展示
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>jQuery 示例:展示用户列表</title>
</head>
<body>
<div id="app">
<ul>
</ul>
</div>
<script src="https://code.jquery.com/jquery-3.5.0.min.js"></script>
<script>
$(document).ready(function() {
$("#app").children("ul").append("<li>张三</li>")
$("#app").children("ul").append("<li>李四</li>")
$("#app").children("ul").append("<li>王麻子</li>")
});
</script>
</body>
</html>
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:
<div id="app-1">
<h1>
hello {{ nameMsg }}
</h1>
</div>
var vm1 = new Vue({
el: '#app-1',
data: {
nameMsg: 'world!'
}
})
通过Vue 实例的data 选项,可以声明应用内需要双向绑定的数据,data 选项中的name 字段, 就是Vue 需要绑定的数据。而Vue实例本身也代理了data 对象里的所有属性。看起来这跟渲染一个字符串模板非常类似,但是 Vue 在背后做了大量工作。现在数据和 DOM 已经被建立了关联,所有东西都是响应式的。要怎么确认呢?在浏览器运行之后,打开浏览器的 JavaScript 控制台 (就在这个页面打开),并修改 vm1.nameMsg = '张三'
,改变其值,将看到上例相应地更新。
请注意:不再和 HTML 直接交互了。一个 Vue 应用会将其挂载到一个 DOM 元素上 (对于这个例子是 #app-1) 然后对其进行完全控制。那个 HTML 是入口,但其余都会发生在新创建的 Vue 实例内部。
除了文本插值,还可以像这样来绑定元素属性
:
<div id="app-2">
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
var vm2 = new Vue({
el: '#app-2',
data: {
message: '页面加载于 ' + new Date().toLocaleString()
}
})
这里遇到了一点新内容。看到的 v-bind
被称为指令。指令带有前缀 v-
,以表示它们是 Vue 提供的特殊属性
。它们会在渲染的 DOM 上应用特殊的响应式行为。在这里,该指令的意思是:“将这个元素节点的title
属性和 Vue 实例的 message
属性保持一致”。
如果再次打开浏览器的 JavaScript 控制台,输入 vm2.message = '新消息'
,就会再一次看到这个绑定了 title 属性的 HTML 已经进行了更新。
控制切换一个元素是否显示:
<div id="app-3">
<p v-if="seen">现在你看到我了</p>
</div>
var vm3 = new Vue({
el: '#app-3',
data: {
seen: true
}
})
继续在控制台输入 vm3.seen = false
,会发现之前显示的消息消失了。
这个例子演示了不仅可以把数据绑定到 DOM 文本或元素属性,还可以绑定到 DOM 结构,此处用到了v-if
指令。此外,Vue 也提供一个强大的过渡效果系统,可以在 Vue 插入
/ 更新
/移除
元素时自动应用过渡效果。
还有其它很多指令,每个都有特殊的功能,随着学习的逐渐深入,将会了解和掌握。再了解一个v-for
指令可以绑定数组或集合对象的数据来渲染一个项目列表:
<div id="app-4">
<ol>
<li v-for="book in books">
{{ book.text }}
</li>
</ol>
</div>
var vm4 = new Vue({
el: '#app-4',
data: {
books: [{
text: 'JavaScript程序设计'
},
{
text: 'Vue前端框架技术'
},
{
text: 'Flask后端框架技术'
}]
}
})
在控制台里,输入 vm4.books.push({ text: 'Java程序设计' })
,将会发现列表最后添加了一个新项目。
为了让用户和应用进行交互,可以用 v-on
指令添加一个事件监听器
,通过它调用在 Vue 实例中定义的方法reverseMessage
:
<div id="app-5">
<p>{{ message }}</p>
<button v-on:click="reverseMessage">反转消息</button>
</div>
var vm5 = new Vue({
el: '#app-5',
data: {
message: 'Hello 张三!'
},
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})
注意:在 reverseMessage
方法中,更新了应用的数据状态message
,但没有触碰 DOM——所有的 DOM 操作都由 Vue 来处理,编写的代码只需要关注逻辑层面即可。
Vue 还提供了 v-model
指令,它能轻松实现表单输入
和数据状态message
之间的双向绑定。
<div id="app-6">
<p>{{ message }}</p>
<input v-model="message">
</div>
var vm6 = new Vue({
el: '#app-6',
data: {
message: 'Hello 王麻子!'
}
})
每个 Vue 应用都是通过构造函数Vue
创建一个Vue 的根实例,并启用多个选项开始:
var vm = new Vue({
// 选项属性
})
变量vm表示对这个Vue 实例的引用,代表了 MVVM 模型中的ViewModel,这个变量名vm
表示了 Vue 实例。当创建一个 Vue 实例时,可以传入一个包含多个选项属性的对象。使用这些选项属性来创建想要的行为
。
传入Vue构造函数的对象参数,其中必不可少的一个选项属性就是el
,其值为一个字符串形式的选择器,或者是DOM的元素对象。若为字符串,则是与css 选择器
相同的表示方式,若是DOM的元素对象,则使用document.getElementById()
或其它获取元素对象的方式。el
提供一个在页面上已存在的DOM元素作为Vue实例的挂载目标:
<div id="app"></div>
var vm = new Vue({
el: '#app'
})
// 或者
var vm = new Vue({
el: document.getElementById('app')
})
在实例挂载成功后,可以通过vm.$el
来访问该元素。Vue 提供了很多常用的实例属性与方法,都以$
开头。如果在实例化时存在这个选项,实例将立即进入编译过程,否则,需要显示调用这个vm.$mount()
手动开启编译。
提供的元素只能作为挂载点,所有的挂载元素会被Vue生成的DOM替换。因此不推荐挂载根实例到<html>
或<body>
上。如果render
函数和template
属性都不存在,挂载DOM元素的HTML会被提取出来用作模板,此时,必须使用独立构建(编译器 + 运行时)的Vue库。进一步的解释就是:如果存在render
函数或template
属性,则挂载元素会被Vue
生成的DOM
替换;否则,挂载元素所在的HTML
会被提取出来用作模版。
vue实例中的el属性
、template属性
、render函数
都是vue对象对应的HTML元素(DOM对象),它们存在时有一个优先级的顺序:el < template < render
,Vue会选择其中优先级高的作为HTML输出:
<div id="app">
<p>我是{{fname}},通过el出来的。</p>
</div>
var vm = new Vue({
el:"#app",
template: "<div><p>我是{{fname}},通过template出来的。</p></div>",
data: {
fname: '张三'
},
render:function(h){
// 不能使用“双大括号”语法 ,因为Vue只是把render函数的返回值放在HTML里,而不进行再次的绑定。
// Vue 在调用 render 方法时,会传入一个 createElement 函数作为参数,这里的 h 的实参是 createElement 函数
return h('h1', '我是'+this.fname+',通过render出来的。')
}
});
以上会使用render函数的内容,因为它的优先级高。render函数发挥了 JavaScript 最大的编程能力。
当一个 Vue 实例被创建时,它将data
选项属性的对象中的所有的property
特性加入到 Vue 的响应式系统中。当这些property
特性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。通过Vue 实例的data
选项属性,可以声明应用内需要双向绑定的数据。所有会用到的数据都应该预先在data
内声明,这样不至于将数据散落在业务逻辑中。
// 数据对象
var mydata = { msg: 3 }
// 该对象被加入到一个 Vue 实例中
var vm = new Vue({
data: mydata
})
// 获得这个实例上的 property与返回源数据中对应的字段作比对。
// 它们之间默认建立了双向绑定,当修改其中任意一个时,另一个也会一起变化。
// 切换到Console:
> vm.msg == mydata.msg
< true // =>true
// 设置 property 也会影响到原始数据
> vm.msg = 5
< 5
> mydata.msg
< 5 // => 5
// ……反之亦然
> datamy.msg = 6
< 6
> vm.msg
< 6 // => 6
当这些数据改变时,视图会进行重渲染。值得注意的是只有当实例被创建时就已经存在于 data
选项中的 property 才是响应式的。也就是说如果你添加一个新的 property,例如:
> vm.myname = '张三'
那么对 myname
的改动将不会触发任何视图的更新。若是晚些时候需要一个 property,不过一开始它的值为空或不存在,则仅需要设置一些初始值。例如:
data: {
newStudent: {
name: '',
gender: '',
age: 18,
tel: ''
},
visitCount: 0,
hideCompletedStudent: false,
students: [],
error: null
}
这里有一个方法使用 Object.freeze()
,它会阻止修改现有的 property,即响应系统无法再追踪变化。
var obj = {
msg: 'hello'
}
Object.freeze(obj) //使用Object.freeze()固化obj对象
new Vue({
el: '#app',
data: obj
})
<div id="app">
<p>{{ msg }}</p>
<!-- 这里的 msg 不会更新! -->
<button v-on:click="msg = 'world'">更改</button>
</div>
除了数据 property,Vue 实例还有一些有用的实例特性与方法
。它们都有前缀 $
,以便与用户定义的 property 区分开来。例如:
var mydata = { val: 1 }
var vm = new Vue({
el: '#app',
data: mydata
})
//Console
> vm.$data === mydata // => true
< true
> vm.$el === document.getElementById('app') // => true
< true
// $watch 是一个实例方法
vm.$watch('val', function (newValue, oldValue) {
// 这个回调将在 `vm.val` 改变后调用
})
每个Vue 实例创建时,都要进行一系列的初始化过程,根据相应的情况,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时也会调用相应的称为生命周期钩子的函数,可以利用这些钩子函数,在不同阶段添加代码,以执行相应的业务逻辑。比较常用的生命周期钩子函数有:
render
函数首次被调用。该钩子在服务器端渲染期间不被调用。el
被新创建的 vm.$el
替换了。第一个业务逻辑从在这里开始。如果根实例挂载到了一个文档(document)内的元素上,当 mounted
被调用时 vm.$el
也在文档内。该钩子在服务器端渲染期间不被调用。watcher
取而代之。该钩子在服务器端渲染期间不被调用。图 2展示了实例的生命周期。这些钩子与el
和data
选项属性类似,也是作为选项写入Vue 实例内,并且钩子的this 指向的是调用它的Vue 实例:
<div id="app"></div>
var vm = new Vue({
el: '#app',
data: {
msg: 'hello'
},
created: function () {
// `this` 指向 vm 实例
console.log('msg 是: ' + this.msg); // => "msg 是: hello"
},
mounted: function () {
console .log (this.$el); // <div id="app"></div>
}
})
图 2. Vue生命周期
Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。
在实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。
如果熟悉虚拟 DOM 并且偏爱 JavaScript 编程,也可以不用模板,直接写渲染 (render) 函数,使用可选的 JSX 语法。
文本:
使用“Mustache”语法 (双大括号
) “{{ }}”是最常见的文本插值方法,它会自动将双向绑定的数据实时显示出来,
<div id="app">
<span>信息: {{ msg }}</span>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg:'爱校码:'
}
});
</script>
双大括号标签将会被替代为对应数据对象上 msg
属性(property
)的值。无论何时,通过任何方式使得绑定的数据对象上msg
属性(property
)的值发生了改变,插值处双大括号的内容都会被实时更新。
原始 HTML:
双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,需要使用 v-html 指令:
<div id="app">
<p>使用双大括号: {{ rawHtml }}</p>
<p>使用 v-html 指令: <span v-html="rawHtml"></span></p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
rawHtml:'<span style="color:green">这里应当是绿色</span>'
}
});
</script>
以上的输出结果:
这里的 span 的内容将会被替换成为属性 (property) rawHtml
的值,直接作为 HTML——会忽略解析属性 (property) 值中的数据绑定。
HTML属性(attribute):
双大括号语法不能作用在 HTML属性(attribute)上,遇到这种情况应该使用 v-bind
指令:
<div id="app">
<a v-bind:href="url">爱校码</a>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
url:'http://www.ischoolcode.cn'
}
});
</script>
使用 JavaScript 表达式:
在双打括号的标签中,除了简单的绑定属性 (property)的值外,还可以使用JavaScript 表达式进行简单的运算、三元运算等。
<div id="app">
{{ number - 5 }}
{{ ok ? '确定' : '取消' }}
{{ msg.split('').reverse().join('') }}
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
number:55,
ok:false,
msg:'ischoolcode'
}
});
</script>
这些表达式会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。每个绑定都只能包含单个表达式,不支持语句和流控制。而在表达式中,不能使用用户自定义的全局变量, 只能使用Vue 白名单内的全局变量, 例如Math 和Date 。所以下面的例子都不会生效。
<!-- 这是语句,不是表达式 -->
{{ var n = 5 }}
<!-- 流控制不会生效,请使用三元表达式 -->
{{ if (ok) { return msg } }}
指令 (Directives) 是带有 v-
前缀的特殊属性(attribute)。指令属性(attribute) 的值预期是单个 JavaScript 表达式 (v-for
是例外情况)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。以v-if 为例:
<p v-if="seen">现在看到了</p>
这里,v-if
指令将根据表达式 seen 的值的真假来决定插入/移除 <p>
元素。
参数:
一些指令能够接收一个“参数”,在指令名称之后以冒号表示。例如,v-bind 指令可以用于响应式地更新 HTML 属性(attribute):
<img v-bind:src="imgUrl">
在这里 src 是参数,告知 v-bind 指令将该元素的src属性(attribute) 与表达式 imgUrl
的值绑定。
再有 v-on
指令,它用于监听 DOM 事件:
<a v-on:click="doHandler">...</a>
在这里参数是监听的事件名click
。doHandler
是事件处理方法。
动态参数:
可以用方括号括起来的 JavaScript 表达式作为一个指令的参数:
<a v-bind:[attributeName]="url"> ... </a>
这里的 attributeName
会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。如果 Vue 实例有一个 data
属性(property)为 attributeName
,其值是 "href"
,那么这个绑定将等价于v-bind:href
。
同样地,你可以使用动态参数为一个动态的事件名绑定处理函数:
<a v-on:[eventName]="doSomething"> ... </a>
在这当中,当 eventName
的值为 "click"
时,v-on:[eventName]
将等价于 v-on:click
。
修饰符:
修饰符 (modifier) 是以点号 .
指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent
修饰符告诉 v-on
指令对于触发的事件调用 event.preventDefault()
;.stop
修饰符告诉 v-on
指令对于触发的事件调用 event.stopPropagation()
。还有其它的像.capture
、.self
、.once
、.passive
等修饰符。
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit">...</form>
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis">...</a>
事件处理方法:
许多事件处理逻辑会很复杂,直接写JavaScript 代码在 .stop.stopv-on 指令中是不可行的。因此 v-on
可以绑定一个需要调用的方法名称。这些方法都写在 Vue 实例的methods
选项属性内,并且是函数的形式,函数内的this
指向的是当前Vue实例本身,可以直接使用this.xxx
的形式来访问或修改数据。在清单4 中,事件处理方法handleClose
位于methods
选项属性内,而其内的方法也被Vue实例代理了,直接通过 this.close()调用了其内的 close()函数方法。
清单 4 methods
选项属性内的事件处理方法
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script src = "https://unpkg.com/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<p v-if="show" >{{msg}}</p>
<button v-on:click="handleClick">{{btn}}</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
show : true,
msg:"",
btn:""
},
methods : {
handleClick: function() {
if (this.show) {
this.close();
}else{
this.open();
}
},
close : function () {
this.show= false ;
this.btn = '点击显示';
},
open : function () {
this.show= true ;
this.btn = '点击隐藏';
},
init: function (text,bv) {
this.msg = text;
this.btn = bv;
}
},
mounted: function () {
this.init('前端框架技术','点击隐藏');
}
});
</script>
</body>
</html>
v-
前缀作为一种视觉提示,用来识别模板中 Vue 特定的属性(attribute)。在使用 Vue.js 为现有标签添加动态行为 (dynamic behavior) 时,v-
前缀很有帮助,然而,对于一些频繁用到的指令来说,就会感到使用繁琐。同时,在构建由 Vue 管理所有模板的单页面应用程序 (SPA) 时,v-
前缀也变得没那么重要了。因此,Vue 为 v-bind
和 v-on
这两个最常用的指令,提供了特定简写。有时将这种缩写称为语法糖。
v-bind
缩写:
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>
v-on
缩写:
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
它们看起来可能与普通的 HTML 略有不同,但 :
与 @
对于属性(attribute) 名来说都是合法字符,在所有支持 Vue 的浏览器都能被正确地解析。而且,它们不会出现在最终渲染的标记中。缩写语法是完全可选的。
Vue.js 允许自定义过滤器,可被用于一些常见的文本格式化。添加一个管道符号 “|
” 对数据进行过滤,过滤的规则是自定义的, 通过给 Vue 实例添加选项filters
来设置。过滤器可以用在两个地方:双大括号插值和 v-bind
表达式 。其被添加在 JavaScript 表达式的尾部。
<!-- 在双大括号中 -->
{{ message | capitalize }} // capitalize是将message进行大写的过滤器
<!-- 在 v-bind 中 -->
<div v-bind:id="rawId | formatId"></div> // formatId 是将rawId进行格式化的过滤器
可以在一个组件的选项中定义本地的过滤器:
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
或者在创建 Vue 实例之前全局定义过滤器:
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
new Vue({
// ...
})
当全局过滤器和局部过滤器重名时,会采用局部过滤器。
过滤器可以串联:
{{ message | filterA | filterB }}
在这里的filterA
被定义为接收单个参数的过滤器函数,表达式 message 的值将作为参数传入到函数中。然后继续调用同样被定义为接收单个参数的过滤器函数filterB
,将filterA
的结果传递到filterB
中。
过滤器是 JavaScript 函数,因此可以接收参数:
{{ message | myfilter('arg1', arg2) }}
在这里,myfilter
被定义为接收三个参数的过滤器函数。其中message
的值作为第一个参数,普通字符串'arg1'
作为第二个参数,表达式变量arg2
的值作为第三个参数。
为了实时显示日历时间,清单 5 设计了一个对日期时间进行格式处理的过滤器:
清单 5. 按照yyyy-MM-dd HH:mm:ss格式显示
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script src = "https://unpkg.com/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
{{ date | formatDate }}
</div>
<script>
let _this;
var vm = new Vue({
el: '#app',
data: {
date: new Date()
},
methods: {
hdate: function(value) {
return value < 10 ? '0' + value : value;
}
},
filters: {
formatDate: function(value) {
var date = new Date(value);
var year = date.getFullYear();
var month = _this.hdate(date.getMonth() + 1);
var day = _this.hdate(date.getDate());
var hours = _this.hdate(date.getHours());
var minutes = _this.hdate(date.getMinutes());
var seconds = _this.hdate(date.getSeconds());
return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds;
}
},
beforeCreate:function(){
_this = this; //将变量 _this指向 Vue 实例 this。
},
mounted:function() {
this.timer = setInterval(function() {
_this.date = new Date(); //修改数据 date
}, 1000);
},
beforeDestroy: function() {
if(this.timer) {
clearInterval(this.timer); //销毁前消除定时器
}
}
})
</script>
</body>
</html>
博文最后更新时间: