官网文档:https://cn.vuejs.org/v2/guide/
vue下载:https://cdn.staticfile.org/vue/2.2.2/vue.min.js
1.Vue的引入:
<script src="vue.min.js"></script>
2.Vue的数据绑定,MVVM模式(Model-View-ViewModel)
注意:所写的Vue的view必须都包含在定义的id内,即el:“#app”,都在这个id内
html
<!-- 创建一个view -->
<!-- 利用双大括号实现文本插值 -->
<div id="app">
{{mess}}
</div>
js
//创建一个model
var messData = {
"mess": "我是一段文本"
}
// 创建一个 Vue 实例或 "ViewModel"
// 它连接 View 与 Model
new Vue({
el: "#app",//就是上面绑定视图层的id
data: messData
})
写法也可以改成下面这种,合并在一起写:
new Vue({
el: "#app",
data: {
"mess": "我是一段文本"
}
})
使用Vue的过程就是定义MVVM各个组成部分的过程的过程。
- 定义View
- 定义Model
- 创建一个Vue实例或"ViewModel",它用于连接View和Model
3.双向绑定示例
<!-- 创建一个view -->
<!-- input这里,通过v-model实现双向数据绑定,这里input的值实时改变,p的值也会实时改变,注意这里v-model插入的值,不需要用大括号包起来 -->
<div id="app">
<p>{{mess}}</p>
<input type="text" v-model="mess">
</div>
将mess绑定到文本框,当更改文本框的值时,<p>{{ mess}}</p>
中的内容也会被更新。同时改变mess的值,input文本框的值也会改变
4.
Vue.js的常用指令
文档:https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4
上面用到的v-model
是Vue.js常用的一个指令,那么指令是什么呢?
Vue.js的指令是以v-开头的,它们作用于HTML元素,指令提供了一些特殊的特性,将指令绑定在元素上时,指令会为绑定的目标元素添加一些特殊的行为,我们可以将指令看作特殊的HTML特性(attribute)。
Vue.js提供了一些常用的内置指令,接下来我们将介绍以下几个内置指令:
- v-if指令
- v-show指令
- v-else指令
- v-else-if 指令
- v-for指令
- v-bind指令
- v-on指令
- v-model 双向数据绑定
- v-once 只渲染元素和组件一次
- v-html 解析带有html标签的文本
v-if指令
v-if
是条件渲染指令,它根据表达式的真假来删除和插入元素,它的基本语法如下:
v-if="expression"
expression是一个返回bool值的表达式,表达式可以是一个bool属性,也可以是一个返回bool的运算式。例如:
<div id="app">
<h1>Hello, Vue.js!</h1>
<h1 v-if="yes">Yes!</h1>
<h1 v-if="no">No!</h1>
<h1 v-if="age >= 25">Age: {{ age }}</h1>
<h1 v-if="name.indexOf('jack') >= 0">Name: {{ name }}</h1>
</div>
注意:所有的数据绑定Vue都支持使用 JavaScript 表达式 例如上面使用的三元表达式,indexOf,split 等等使用都是支持的
这里v-if,可以是bool属性,也可以用来做运算
var vm = new Vue({
el: '#app',
data: {
yes: true,
no: false,
age: 28,
name: 'keepfool'
}
})
可以直接打印出:
console.log(vm.yes)--->true
注意:v-if指令是根据条件表达式的值来执行元素的插入或者删除行为。
v-show指令
v-show
也是条件渲染指令,和v-if指令不同的是,使用v-show
指令的元素始终会被渲染到HTML,它只是简单地为元素设置CSS的style属性。
他跟上面v-if的作用上功能是类似的,区别是v-if为false的时候,这个dom结构不会存在,但是v-show为false的时候,dom还是存在的,不过是display:none了
把以上v-if的地方改成v-show,对比下他们的odm结构
v-if v-show
在页面展示出来的效果都是一样的:
v-else指令
可以用v-else
指令为v-if
或v-show
添加一个“else块”。
注意:
(1).v-else
元素必须立即跟在v-if
或v-show
元素的后面——否则它不能被识别。
(2).v-else
元素是否渲染在HTML中,取决于前面使用的是v-if
还是v-show
指令。(3).只有当v-if和v-show为false时,才会走v-else。如果v-if是true时,
后面的v-else
不会渲染到HTML中;v-show
为tue,后面的v-else会
渲染到HTML了,但是display:none 隐藏掉了
<div id="app">
<h1 v-if="yes">Yes!</h1>
<h1 v-else>No!</h1>
<h1 v-show="age >= 25">Age: {{ age }}</h1>
<h1 v-show="name.indexOf('jack') >= 0">Name: {{ name }}</h1>
</div>
var vm = new Vue({
el: '#app',
data: {
yes: false,
no: false,
age: 28,
name: 'keepfool'
}
})
v-for指令
v-for
指令基于一个数组渲染一个列表,它和JavaScript的遍历语法相似:可以遍历数组对象,数组,对象,数字
v-for="item in items"
items是一个数组,item是当前被遍历的数组元素。
注意:
(1).这里需要遍历多个li的时候,直接v-for绑定在li上,如果绑定在ul上,会渲染多个ul包裹一个li的结构
(2).v-for="item in items" 。in前面的是自定义的for的value, in后面的是遍历的变量名
(3)v-for
还支持一个可选的第二个参数,即当前项的索引。<div v-for="(value, name) in object"></div>
且支持传入第三个参数<div v-for="(value, name, index) in object"></div>
(4).你也可以用 of
替代 in
作为分隔符 。 <div v-for="item of items"></div>
可以支持遍历 对象,数组,一个数值,例如遍历10这个值,遍历数值的时候,最小下标是1,例如遍历时,渲染出来的是1-10
(5).为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性:<div v-for="item in items" v-bind:key="item.id"></div>,设置成key值的话必须是唯一的,不推荐使用index来作为key,可以是时间戳加上一个自增的数字
<div id="app">
<ul>
<li v-for="item in arr">{{item.name}}</li>
<!-- <li v-for="item in arr1">{{item}}</li> -->
<!--<li v-for="value in pageCount">{{value}}</li>-->
</ul>
</div>
var vm = new Vue({
el: '#app',
data: {
arr: [
{ name: 'zhaosan', age: 18 },
{ name: 'lsi', age: 5 },
{ name: 'ww', age: 18 },
{ name: 'xiao', age: 6 }
],
arr1: [1, 3, 4, 5, 6],
pageCount: 10
}
})
v-for="(item, index) in items" 传入第二个参数,当前项的索引
<ul id="example-2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
var example2 = new Vue({
el: '#example-2',
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
可以传入第三个参数,拿到属性名,属性值,索引
还可以用第三个参数作为索引:
<div id="app">
<ul id="example-2">
<li v-for="(value, index,indexs) in object">
{{ value }} - {{ index }} - {{ indexs }}
</li>
</ul>
</div>
var vm = new Vue({
el: "#app",
data: {
parentMessage: 'Parent',
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
<div v-for="item in items" v-bind:key="item.id">
<!-- 内容 -->
</div>
避免 v-if 和 v-for 用在一起
这里假如需要操控数据,例如给arr增加一项,则可以通过以下写法:
vm.arr.push({ name: '我我我', age: 100})
则,arr就变成了5项数据了
v-bind指令
v-bind
指令可以在其名称后面带一个参数,中间放一个冒号隔开,这个参数通常是HTML元素的特性(attribute),例如:v-bind:class, v-bind:title 是加属性的
v-bind:argument="expression"
例如:以下实现给元素绑定一个active的class,这里实现的给1-3的li下面的a加上了active的class
<div id="app">
<ul class="pagination">
<li v-for="n in pageCount">
<a href="javascripit:void(0)" v-bind:class="activeNumber >= n ? 'active' : ''">{{ n }}</a>
</li>
</ul>
</div>
var vm = new Vue({
el: '#app',
data: {
activeNumber: 3,
pageCount: 10
}
})
效果如下:
div id="app-2">
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
var app2 = new Vue({
el: '#app-2',
data: {
message: '页面加载于 ' + new Date().toLocaleString()
}
})
假如需要将一个对象的全部属性,都通过v-bind绑定上去,写法如下:
如果你想把一个对象
的所有属性
作为 prop 进行传递,可以使用不带任何参数的 v-bind
(即用 v-bind 而不是 v-bind:prop-name)
html:
<div id="app">
<p v-bind="todo">wenben</p>
</div>
js:
var vm = new Vue({
el: "#app",
data: {
todo: {
text: 'Learn Vue',
isComplete: 'false'
}
}
})
效果:
v-on指令
v-on
指令用于给监听DOM事件,它的用语法和v-bind是类似的,例如监听<a>元素的点击事件:
<a v-on:click="doSomething">
有两种形式调用方法:绑定一个方法(让事件指向方法的引用),或者使用内联语句。
注意:
(1).事件和方法要写在methods中
(2).事件中的this指向的就是new出来的这个vue对象
<div id="app">
<div>
<!--click事件直接绑定一个方法-->
<button v-on:click="clickMe">我是一个按钮</button>
<!--click事件使用内联语句-->
<button v-on:click="clickThis('hello')">我是一个</button>
</div>
</div>
var vm = new Vue({
el: '#app',
data: {
activeNumber: 3,
pageCount: 10
},
// 在 `methods` 对象中定义方法
methods: {
clickMe: function() {
// 方法内 `this` 指向 vm
console.log(this.activeNumber)
},
clickThis: function(msg) {
console.log(msg)
}
}
})
v-bind和v-on的缩写
Vue.js为最常用的两个指令v-bind
和v-on
提供了缩写方式。v-bind指令可以缩写为一个冒号,v-on指令可以缩写为@符号。
<!--完整语法-->
<a href="javascripit:void(0)" v-bind:class="activeNumber === n + 1 ? 'active' : ''">{{ n + 1 }}</a>
<!--缩写语法-->
<a href="javascripit:void(0)" :class="activeNumber=== n + 1 ? 'active' : ''">{{ n + 1 }}</a>
<!--完整语法-->
<button v-on:click="greet">Greet</button>
<!--缩写语法-->
<button @click="greet">Greet</button>
v-model
预期:随表单控件类型不同而不同。
限制:
<input>
<select>
<textarea>
- components
修饰符:
修饰符 (modifier) 是以半角句号 .
指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。
html:
<div id="app">
<p>{{msg}}</p>
<!--.lazy 取代 input 监听 change 事件 input的msg改变了,但是上面p中的内容不会跟着变 -->
<input v-model.lazy="msg" >
<!-- .number 输入的是数字时,会将输入类型转化为数字类型;数字是文字等字符串则无效 -->
<input v-model.number="msg" >
<!--.trim 会去除输入时两头的空格 -->
<input v-model.trim="msg" >
</div>
js:
let vm = new Vue({
el: '#app',
data: {
msg:'aa',
age:18,
trims:'wenben'
}
});
v-once
文档:https://cn.vuejs.org/v2/api/#v-once
- 不需要表达式
- 只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。当数据改变时,插值处的内容不会更新。
例:当修改input框的值时,使用了v-once指令的p元素不会随之改变,而第二个p元素时可以随之改变的
html:
<div id="app">
<p v-once>{{msg}}</p> //msg不会改变
<p>{{msg}}</p>
<p>
<input type="text" v-model = "msg" name="">
</p>
</div>
js:
let vm = new Vue({
el : '#app',
data : {
msg : "hello"
}
});
v-html
- 双大括号会将数据解释为普通文本,而非 HTML 代码,解析不了标签,样式等
- 语法: v-html='mess'
html:
<div id="app">
<p id="a">Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: </p>
</div>
js:
let vm = new Vue({
el: '#app',
data: {
rawHtml: '<span style="color:red">利用vue添加了插入一个span 元素</span>' //元素内数据代码 message
}
});
以上效果如下:标签没有被解析,而是直接输出了
解决方法就是:
通过 v-html="rawHtml",输出真正的HTML
html:
<div id="app">
<p id="a" v-html="rawHtml">Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: </p>
</div>
js:
let vm = new Vue({
el: '#app',
data: {
rawHtml: '<span style="color:red">利用vue添加了插入一个span 元素</span>' //元素内数据代码 message
}
});
效果如下:
5.组件化应用构建
Vue.component ()定义组件:一个组件本质上是一个拥有预定义选项的一个 Vue 实例
注意:
(1).定义的组件名称跟使用时要一致,
(2).定义组件 Vue.component 必须写在 new Vue的前面,否则不生效
(3).组件是可复用的,例如这里通过 Vue.component定义了一个my-comp的组件后,在视图中可以多次使用,而且互不干扰
(5).单个根元素,每个组件必须只有一个根元素。
<div id="app">
<!--my-comp就是在vue中定义的组件名称 -->
<my-comp></my-comp>
<my-comp></my-comp>
<my-comp></my-comp>
</div>
//my-comp:定义的组件名称
Vue.component('my-comp',{
template:'<p>我是一个组件的内容</p>'
})
var vm=new Vue({
el:"#app",
data:{
}
})
上面定义的组件文本是写死的,那怎么可以动态渲染这个组件呢
方法:这里通过v-bind,将属性绑定上,然后在定义的component组件中,通过props属性,将定义的属性拿到,传给组件
<div id="app">
<!--my-comp就是在vue中定义的组件名称 -->
<my-comp v-for="item in groceryList" v-bind:title="item" v-bind:ids="item.id">
</my-comp>
</div>
//my-comp:定义的组件名称
Vue.component('my-comp',{
props:['title','ids'],
template:'<div>{{title.text}}<p>{{ids}}</p></div>'
})
new Vue({
el: "#app",
data: {
groceryList: [
{ id: 0, text: '蔬菜' },
{ id: 1, text: '奶酪' },
{ id: 2, text: '随便其它什么人吃的东西' }
]
}
})
效果:
还可以: 以下实现点击,自动加1的效果
<div id="app">
<!--my-comp就是在vue中定义的组件名称 -->
<my-comp>
</my-comp>
</div>
//my-comp:定义的组件名称
Vue.component('my-comp',{
data:function(){
return {
count:0
}
},
template:'<div v-on:click="count++">这是{{count}}的值</div>'
})
注册组件的方式:
全局注册:
Vue.component('component-a', { /* ... */ })
new Vue({ el: '#app' })
局部注册:
var ComponentA = { /* ... */ }
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
使用 prop 传递数据:
在 Vue 中,父子组件的关系可以总结为 prop
向下传递,事件
向上传递。父组件通过 prop
给子组件下发数据,子组件通过事件
给父组件发送消息。
Vue.component('child', {
// 声明 props
props: ['message'],
// 就像 data 一样,prop 也可以在模板中使用
// 同样也可以在 vm 实例中通过 this.message 来使用
template: '<span>{{ message }}</span>'
})
<child message="hello!"></child>
结果:hello!
HTML 特性是不区分大小写的。所以,当使用的不是字符串模板时,camelCase (驼峰式命名) 的 prop 需要转换为相对应的 kebab-case (短横线分隔式命名):
Vue.component('child', {
// 在 JavaScript 中使用 camelCase
props: ['myMessage'],
template: '<span>{{ myMessage }}</span>'
})
<!-- 在 HTML 中使用 kebab-case -->
<child my-message="hello!"></child>
如果你使用字符串模板,则没有这些限制。
因为组件是可复用的 Vue 实例,所以它们与 new Vue
接收相同的选项,例如 data
、computed
、watch
、methods
以及生命周期钩子等。仅有的例外是像 el
这样根实例特有的选项。
一个组件的 data
选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
data: function () {
return {
count: 0
}
}
当需要传参比较复杂时的处理:
当需要传递多个参数时,这样写会很复杂:
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:title="post.title"
v-bind:content="post.content"
v-bind:publishedAt="post.publishedAt"
v-bind:comments="post.comments"
></blog-post>
改写:
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-post>
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<div v-html="post.content"></div>
</div>
`
})
Vue.extend():另一种注册组件的方法
文档:https://segmentfault.com/a/1190000012826671
html:
<my-comp></my-comp>
js:
定义组件方法1:
Vue.component('my-comp',{
template:'<p>我是直接定义的模板</p>'
})
new Vue({
el: "#app",
data: {
}
})
定义组件方法2:使用Vue.extend()定义组件
var comp=Vue.extend({
template:'<p>我是直接定义的模板</p>'
})
Vue.component('my-comp',comp);
new Vue({
el: "#app",
data: {
}
})
$mount:用于挂载
文档:https://segmentfault.com/a/1190000012826671
注意:
(1).通过$mount挂载后,会直接替换掉当前的dom;
(2). $mount(),参数可以是一个class或者id。 跟视图中的对应上就可以
(3).这种用法, 不需要new Vue 都可以直接使用
html:
<div id="app">
<p>我是11</p>
<div id="mount-point"></div>
</div>
js:
var Profile =Vue.extend({
template:'<p>我是直接定义的模板</p>'
})
new Profile().$mount('#mount-point')
结果是:
局部注册
你不必把每个组件都注册到全局。你可以通过某个 Vue 实例/组件的实例选项 components 注册仅在其作用域中可用的组件:
html:
<div id="app">
<my-component></my-component>
</div>
js:
var Child = {
template: '<div>A custom component!</div>'
}
new Vue({
el:"#app",
components: {
// <my-component> 将只在父组件模板中可用
'my-component': Child
}
})
这里组件使用,对于一些特殊的DOM标签,需要注意:
像
<ul>、<ol>、<table>、<select>
这样的元素里允许包含的元素有限制,而另一些像<option>
这样的元素只能出现在某些特定元素的内部。
这种特殊的标签,自定义组件 <my-
component>
会被当作无效的内容,因此会导致错误的渲染结果。变通的方案是使用特殊的 is
特性:
错误写法:
<table id="app">
<my-component></my-component>
</table>正确写法:通过is绑定
<table id="app">
<tr is="my-component"></tr></table>
js:
var Child = {
template: '<div>A custom component!</div>'
}new Vue({
el:"#app",
components: {
// <my-component> 将只在父组件模板中可用
'my-component': Child
}
})
应当注意,如果使用来自以下来源之一的字符串模板,则没有这些限制:
<script type="text/x-template">
JavaScript
内联模板字符串 (例如:template: '...'
).vue
组件 (.vue
)
因此,请尽可能使用字符串模板。
6.css过渡&动画
文档:https://cn.vuejs.org/v2/guide/transitions.html
以下实现一个点击按钮,显示,隐藏的效果,并且加了过渡效果
(1).过渡
css:
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity .5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>
html:
注意这里transition这里的name ,这里fade会被替换成fade-enter,fade-leave等等,跟上面的css类名对应
<div id="demo">
<button v-on:click="show=!show">按钮</button>
<transition name="fade">
<p v-if="show">显示</p>
</transition>
</div>
js:
new Vue({
el: '#demo',
data: {
show: true
}
})
过渡的类名
在进入/离开的过渡中,会有 6 个 class 切换。
-
v-enter
:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。 -
v-enter-active
:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。 -
v-enter-to
: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时v-enter
被移除),在过渡/动画完成之后移除。 -
v-leave
: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。 -
v-leave-active
:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。 -
v-leave-to
: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时v-leave
被删除),在过渡/动画完成之后移除。
对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 <transition>
,则 v-
是这些类名的默认前缀。如果你使用了 <transition name="my-transition">
,那么 v-enter
会替换为 my-transition-enter
。
(2).CSS 动画
CSS 动画用法同 CSS 过渡,区别是在动画中 v-enter
类名在节点插入 DOM 后不会立即删除,而是在 animationend
事件触发时删除。但是他们类名使用都是一样的
css:用到animation实现动画效果
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
Object.freeze()
这会阻止修改现有的属性,也意味着响应系统无法再追踪变化。
var obj = {
foo: 'bar'
}
//Object.freeze(obj),这样操作后,视图中改变foo的值会报错
Object.freeze(obj)
new Vue({
el: '#app',
data: obj
})
Vue 实例还暴露了一些有用的实例属性与方法。它们都有前缀 $
,以便与用户定义的属性区分开来
vm.$ 后面跟的就是vm的属性,区别于其他的
var data = { a: 1 }
var vm = new Vue({
el: '#example',
data: data
})
console.log(data)===等同于 console.log(vm.$data)
$watch:当定义的值改变的时候触发
html:
<div id="app">
<button v-on:click="{{a++}}">加值</button>
</div>
js:
var vm = new Vue({
el: '#app',
data: {
a:11
}
})
vm.$watch('a', function(newValue, oldValue) {
console.log(newValue)
console.log(oldValue)
// 这个回调将在 `vm.a` 改变后调用
})
7.生命周期钩子
created
:实例被创建之后自动立即执行
var vm = new Vue({
el: '#app',
data: {
obj: {
yes: 'shi',
no: "false",
age: 28,
name: 'keepfool'
}
},
created:function(){
// `this` 指向 vm 实例
console.log(this.obj.name)
}
})
//这里页面加载的时候,直接注册的实例,所以页面加载的时候,直接打印出了 'keepfool'
created就是加载实例的时候,直接调用
也有一些其它的钩子,在实例生命周期的不同阶段被调用,如 mounted
、updated
和 destroyed
。生命周期钩子的 this
上下文指向调用它的 Vue 实例。
不要在选项属性或回调上使用箭头函数,比如 created: () => console.log(this.a)
或 vm.$watch('a', newValue => this.myMethod())
。因为箭头函数并没有 this
,this
会作为变量一直向上级词法作用域查找,直至找到为止,经常导致 Uncaught TypeError: Cannot read property of undefined
或 Uncaught TypeError: this.myMethod is not a function
之类的错误。
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
如:数据初始化一般放到created里面,这样可以及早发请求获取数据,
如果有依赖dom必须存在的情况,就放到mounted(){this.$nextTick(() => { /* code */ })}里面
window.onload=function(){
let vm=new Vue({
el:'#itany',
data:{
msg:'welcome to itany'
},
methods:{
update(){
this.msg='欢迎来到南京网博!';
},
destroy(){
// this.$destroy();
vm.$destroy();
}
},
beforeCreate(){
alert('组件实例刚刚创建,还未进行数据观测和事件配置');
},
created(){ //常用!!!
alert('实例已经创建完成,并且已经进行数据观测和事件配置');
},
beforeMount(){
alert('模板编译之前,还没挂载');
},
mounted(){ //常用!!!
alert('模板编译之后,已经挂载,此时才会渲染页面,才能看到页面上数据的展示');
},
beforeUpdate(){
alert('组件更新之前');
},
updated(){
alert('组件更新之后');
},
beforeDestroy(){
alert('组件销毁之前');
},
destroyed(){
alert('组件销毁之后');
}
});
}
8.计算属性(computed)
文档:https://cn.vuejs.org/v2/guide/computed.html
当我们需要在模板中有计算的时候,可以直接运用js的语法计算,但是当这种计算比较频繁时,这样写比较麻烦,写在计算函数中就比较方便,运用计算属性 computed
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
改成下面写法:
属性调用的时候,不需要(),直接写属性名就可以
html:
<div id="app">
<p>{{trims}}</p>
<p>{{jisuan}}</p>
</div>
js:
let vm = new Vue({
el: '#app',
data: {
trims: 'wen-ben'
},
//定义计算属性
computed: {
// 在computed里定义方法,使用的时候直接写方法名
jisuan: function() {
return this.trims.split('').reverse().join('')
}
}
});
效果如下:
如果是需要对后台请求回来的数据进行处理:
//list.js
computed: {
timeHandle: function() {
//这里需要加个闭包的写法,来传入参数
return function(time) {
return time.substr(5, 5).replace(/-/g, '.');
}
}
},
html
//这里调用computed里面的计算函数来处理这个时间的输出
<div class="lis_con">
<h1>{{item.sGameName}}</h1>
<span class="btn-go"></span>
<p>{{timeHandle(item.sDate)}}-{{timeHandle(item.eDate)}}</p>
</div>
计算属性computed的getter和setter:
<div id="root">
{{fullName}}
</div>
<script>
var vm=new Vue({
el: "#root",
data: {
firstName: 'Dell',
lastName: 'Lee',
fullname: 'Dell Lee'
},
computed:{
fullName:{
get: function () {
return this.firstName+" "+this.lastName
},
set: function (value) {
var arr=value.split(" ");
this.firstName=arr[0];
this.lastName=arr[1];
}
}
}
})
同样的效果,我们也可以通过在methods中写一个方法来实现,方法调用的时候需要加() reversedMessage()
<p>Reversed message: "{{ reversedMessage() }}"</p>
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
他们的区分是:
- 属性计算,只在计算的属性发生改变时才会执行,不改变的话则读取的缓存; 方法则每次渲染都会执行
参考:https://www.cnblogs.com/zzliu/p/10778008.html
计算属性 vs 侦听属性
vue中有watch来计算属性,以上这种,我们通过computed,侦听属性更方便
Vue中computed和watch的区别:
计算属性computed :
1. 支持缓存,只有依赖数据发生改变,才会重新进行计算
2. 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
3.computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过的数据通过计算得到的
4. 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
5.如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。
侦听属性watch:
1. 不支持缓存,数据变,直接会触发相应的操作;
2.watch支持异步;
3.监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
4. 当一个属性发生变化时,需要执行对应的操作;一对多;
与computed对比,watch更加适用于监听某一个值的变化并做对应的操作,比如请求后台接口等,而computed适用于计算已有的值并返回结果
1.如果一个数据依赖于其他数据的简易计算处理的,那么使用computed比较合适。
2.如果需要在某个数据变化时做一些事情,使用watch来观察这个数据变化watch: {
number (newVal, oldVal) {//有两个参数,改变后的值,改变前的值
console.log('number has changed: ', newVal)
}
}
9. Class 与 Style 绑定
(1)对象语法:
- 使用对象;例:v-bind:class='{active:classA}'
- 三元表达式
- 直接定义一个对象的形式绑定class :例 v-bind:class="classObject"
- 计算属性来实现
html:
<div id="app">
<p v-bind:class='{active:classA}'>对象语法 绑定class</p>
<p v-bind:class='{active:classA,active1:classB}'>对象语法 绑定多个class</p>
<p v-bind:class='classA?"active":""'>三元绑定class</p>
<p v-bind:class="classObject">内联定义class</p>
</div>
js:
var vm = new Vue({
el: "#app",
data: {
classA: false,
classB: true,
classObject: {
active: true,
'text-danger': true
}
}
})
通过计算属性来实现绑定class:
<div v-bind:class="classObject"></div>
data: {
isActive: true,
error: null
},
computed: {
classObject: function () {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
(2)数组语法
- 直接定义一个数组
- 也可以结合三元表达式一起用
- 结合对象一起用
html:
<div id="app">
<div v-bind:class="[active,ups]">数组绑定的方式</div>
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
</div>
js:
var vm=new Vue({
el:"#app",
data:{
active:"classA",
ups:"on"
}
})
(3).用在组件上
当在一个自定义组件上使用 class
属性时,这些类将被添加到该组件的根元素上面。
Vue.component('my-component', {
template: '<p class="foo bar">Hi</p>'
})
<my-component class="baz boo"></my-component>
HTML 将被渲染为:
<p class="foo bar baz boo">Hi</p>
绑定内联样式
v-bind:style
对象语法
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
activeColor: 'red',
fontSize: 30
}
数组语法
10.条件渲染
只需添加一个具有唯一值的 key
属性即可:
这里的需求是切换这两个 template,input的值也需要相互独立,各不影响
template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
11.数组更新检测
变异方法
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
例如:filter()
、concat()
和 slice()
,它们不会改变原始数组,而总是返回一个新数组。
注意事项
由于 JavaScript 的限制,Vue 不能检测以下数组的变动:
- 当你利用索引直接设置一个数组项时,例如:
vm.items[indexOfItem] = newValue
- 当你修改数组的长度时,例如:
vm.items.length = newLength
同样,还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 现在是响应式的
vm.b = 2
// `vm.b` 不是响应式的
可以先定义,后赋值,则可以是响应式的
对于已经创建的实例,Vue 不允许动态添加根级别的响应式属性。
但是,可以使用 Vue.set(object, propertyName, value)
方法向嵌套对象添加响应式属性。例如,对于:
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
你可以添加一个新的 age
属性到嵌套的 userProfile
对象:
Vue.set(vm.userProfile, 'age', 27)
你还可以使用 vm.$set
实例方法,它只是全局 Vue.set
的别名:
vm.$set(vm.userProfile, 'age', 27)
有时你可能需要为已有对象赋值多个新属性,比如使用 Object.assign()
或 _.extend()
。在这种情况下,你应该用两个对象的属性创建一个新的对象。所以,如果你想添加新的响应式属性
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
12.事件处理
在事件处理程序中调用 event.preventDefault()
或 event.stopPropagation()
是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题,Vue.js 为 v-on
提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
.stop :
等同于JavaScript中的event.stopPropagation()
,防止事件冒泡.prevent :
等同于JavaScript中的event.preventDefault()
,用于取消默认事件,防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播).capture :
与事件冒泡的方向相反,事件捕获由外到内,捕获冒泡.self :
只会触发自己范围内的事件,不包含子元素.once :
只会触发一次.passive:
2.3.0 新增 ,不阻止事件的默认行为
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即元素自身触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
(1).stop
已下效果,点击button的时候,会冒泡到外层包着的两层div的事件,所以会看到控制台打印(1)inner,(2)inner,(3)inner,但是如果我们想要的只想触发button的事件的话,则用.stop <button @click.stop="inner">click</button>
<!-- HTML -->
<div id="demo">
<div @click="outer" style="padding: 20px;background-color:deepskyblue">
<div @click="middle" style="padding: 10px;background-color: darkcyan">
<button @click="inner">click</button>
</div>
</div>
</div>
<!-- JS -->
var demo = new Vue({
el: '#demo',
methods: {
inner: function () {
console.log ('(1)inner')
},
middle: function () {
console.log ('(2)middle')
},
outer: function () {
console.log ('(3)outer')
}
}
})
(2).prevent
某些标签拥有自身的默认事件,比如<a>标签点击后会进行页面的跳转。这类默认事件虽然是冒泡后开始的,但不会因为stop而停止执行。阻止执行这类预设的行为,.prevent就派上用场了。例如已下,加上 .prevent后,就不会跳转了
<a href="http://www.baidu.com" @click.prevent>点击跳转</a>
(3).capture
对比于上面的.stop(),将中间层的点击事件加上.capture修饰符
<div @click="outer" style="padding: 20px;background-color:deepskyblue">
<div @click.capture="middle" style="padding: 10px;background-color: darkcyan">
<button @click="inner">click</button>
</div>
</div>
带修饰符的从外到内依次执行,然后再按正常顺序执行触发的事件。
(4).self
将事件绑定到自身,只有自身才能触发,通常用于避免冒泡事件的影响。对比与上面的stop案例,给中间层加上.self,这个时候点击button的时候,发现 (2)inner没有打印出来,只有点中间层的时候,才会打印(2)inner
(5).once
加上once修饰符以后事件只触发一次,但是不影响事件的冒泡,上层的事件仍然会被触发
例如上面的,给button加上.once后,一直点击,发现 (1)inner 只打印了一次,但是(2)inner,(3)inner每次点击都会打印
(6).passive
这里涉及到一个问题,为什么需要告诉浏览器不阻止事件的默认行为?
原因是这样的,浏览器只会在每次触发监听器的时候,才去判断这次是否有调用preventDefault()来阻止默认行为。这样的判断,在某些场景下会影响交互,像用户通过手势滑动页面时,就没法迅速滚动了,而使用.passive就可以提前告诉浏览器,我们没有用preventDefault阻止默认动作,你也不用反复去判断了,从而提高性能解决卡顿。
不要把 .passive
和 .prevent
一起使用,因为 .prevent
将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive
会告诉浏览器你不想阻止事件的默认行为。
13.按键修饰符
例如:监听键盘 enter键时的keyup事件
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
如果想监听所有键盘的keyup事件,则:
<input v-on:keyup="submit">
按键码
keyCode
的事件用法已经被废弃了并可能不会被最新的浏览器支持。用法是:<input v-on:keyup.13="submit">
记住所有的keyCode
比较困难,为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.right
鼠标修饰符
鼠标修饰符用来限制处理程序监听特定的滑鼠按键。常见的有:
.left
:鼠标左键.middle
:鼠标中间滚轮.right
:鼠标右键
修饰键
可以用如下修饰符开启鼠标或键盘事件监听,使在按键按下时发生响应:
.ctrl
例:<div @click.ctrl="doSomething">Do something</div>,表示点击,且按住ctrl键才触发doSomething事件
.alt
.shift
.meta
14.表单输入绑定
你可以用 v-model
指令在表单 <input>
、<textarea>
及 <select>
元素上创建双向数据绑定。