vue的基础用法

logo.jpg

Vue是一套构建用户界面的渐进式框架。
文档:https://cn.vuejs.org/v2/guide
所有api:https://cn.vuejs.org/v2/api/

模板语法

声明时渲染

Vue.js 的核心是一个允许你采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统。

  • 文本插值
1
2
3
4
5
HTML
<div id="app">
{{ message }}
</div>
  • v-text:更新元素的 textContent
    其实,双花括号就是v-text的语法糖
    1
    2
    3
    <p>{{msg}}</p>
    等同于
    <p v-text="msg"></p>
1
2
3
4
5
6
7
8
JS
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})

此时,#app里的内容会变成Hello Vue

响应式修改:

1
app.message = '我被修改了'

ps:除了数据属性,Vue 实例还提供了一些有用的实例属性与方法,它们都有前缀 $,以便与用户定义的属性区分开来

1
2
3
4
5
6
7
app.$el === document.getElementById('app') //<div id="app">Hello Vue!</div>
app.$data // {message:'Hello Vue!'}
app.$data.message // hello Vue!
等同于
app.message // Hello Vue


  • v-html:更新元素的 innerHTML
1
2
3
<div id="app">
<div v-html="message"></div>
</div>
1
2
3
4
5
6
new Vue({
el: '#app',
data: {
message: '<h1>菜鸟教程</h1>'
}
})

参考文档:https://cn.vuejs.org/v2/guide/
菜鸟教程:vue模板语法

补充知识

  • el:挂载点,不能是body
  • data:数据对象,推荐在实例创建之前就预设好所有的数据
  • 双花括号其实是v-text的语法糖

响应式系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var data = { a: 1 }
var app = new Vue({
data: data //此时,vue的data与原始数据指向同一个地址
})
app.a == data.a // => true
// 修改app.a会影响到原始数据
app.a = 2
data.a // => 2
// ……反之亦然
data.a = 3
app.a // => 3

计算属性computed

双括号里面一般用作声明,所以不推荐里面进行太过复杂的运算,在模板中放入太多的逻辑会让模板过重且难以维护

1
2
3
<div id="app">
{{ message.split('').reverse().join('') }}
</div>

推荐改成计算属性

1
2
3
<div id="app">
{{ reversedMessage }}
</div>

1
2
3
4
5
6
7
8
9
10
11
var app = new Vue({
el: '#app',
data: {
message: 'Hello'
},
computed: {// 计算属性的 getter
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
})

通过修改app.message可以得到不同的结果


除了计算属性,还能通过methods渲染

1
2
3
4
5
HTML
<div id="app">
<p>颠倒字符串: "{{ x() }}"</p>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
JS
new Vue({
el: "#app",
data: {
msg:'12345'
},
methods: {
x: function(){
return this.msg.split('').reverse().join('')
}
}
})

p标签内最终呈现颠倒字符串:54321

计算属性的get和set

计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter:查看在线例子
通过计算属性的setter,我们可以间接修改它所依赖的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<p>{{ fullName }}</p>
computed: {
//写成对象的格式
fullName: {
// getter
get() {
return this.firstName + ' ' + this.lastName
},
// setter
set(newValue) {
const names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
当响应式修改vm.fullName = 'John Doe' 时,set 会被自动调用,然后通过get将fullName这个属性渲染到页面上

【计算属性是通过别的属性计算而来的,所以,直接修改this.fullName的值是没有用的;可以通过计算属性的setter,将它依赖的属性先修改了,从而改变计算属性】

计算属性的get和set实现全选返现功能

1
2
3
4
5
6
7
8
9
10
computed:{
isAll:{
get(){
return this.todos.filter(todo => !todo.done).length === 0
},
set(newVal){
this.todos.forEach(todo => todo.done=newVal)
}
}
}

v-model绑定了isAll,当勾选了这个框,就会调用set

【点击查看例子】

计算属性computed vs 方法methods vs 侦听器watch

计算属性有缓存:https://cn.vuejs.org/v2/guide/computed.html

计算属性是基于它们的依赖进行缓存的,只有在它的相关依赖发生改变时才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
而使用 methods ,每当触发渲染时,函数总会重新调用执行。

来看个具体的例子

1
2
3
4
5
6
7
8
9
10
11
12
<div id="app">
<span>
{{computedMessage}}
{{computedMessage}}
{{computedMessage}}
</span>
<span>
{{calcMessage()}}
{{calcMessage()}}
{{calcMessage()}}
</span>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var app = new Vue({
el: '#app',
data: {
message: 'hi'
},
computed:{
computedMessage(){
console.log('computed')
return 'computed ' + this.message
},
},
methods:{
calcMessage(){
console.log('methods')
return 'calc ' + this.message
}
}
})

【点击查看例子】
打开控制台,可以看到computed打印了1次,而methods打印了3次。

另外,从命名上可以看出,计算属性是一个属性,因此一般用于return一个具体的值,且在双括号中当做属性使用

1
2
<!-- 计算属性 -->
{{ sum }}

而methods一般用于执行方法,当它有return时才与计算属性类似,在双括号中必须执行这个方法

1
2
<!-- 方法 -->
{{ sum() }}

计算属性的应用场景

如果是简单的处理,且最后将处理结果return出去作为属性值,推荐使用计算属性
如果data里的属性是需要依靠其他属性计算得出,就将这个属性移到计算属性里(比如sum需要用到data里的其他属性计算后得出,那么就将这个sum属性移到计算属性里)

  • 求总分
  • 求平均分
  • 处理简单字符串

vue的计算属性,通过调用缓存的sum求出average,提高了性能

1
2
3
4
5
6
7
<div id="app">
数学<input type="text" v-model.number="math">
英语<input type="text" v-model.number="english">
语文<input type="text" v-model.number="chinese">
<br>总分:{{sum}}
<br> 平均分:{{average}}
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var app = new Vue({
el:'#app',
data:{
math:90,
english:85,
chinese:87
},
computed:{
sum(){
return this.math+this.english+this.chinese;
},
average(){
//直接把缓存的sum拿过来除以3
return this.sum/3;
},
}
})

如果用methods,那么每次都会重新调用sum

计算属性 vs 侦听器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
computed:{
fullName(){
return this.firstName + this.lastName;
}
},
watch:{
firstName(newVal){
this.fullName = newVal + this.lastName;
},
lastName(newVal){
this.fullName = this.firstName + newVal
}
}

侦听属性watch

https://cn.vuejs.org/v2/api/#watch

侦听属性watch,当侦听到data里数据的变化时,执行方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
watch:{
//侦听maskSeen的值,如果发生改变就执行函数
maskSeen(newVal,oldVal){
console.log(newVal);
},
//侦听currentUser.id的变化,当发生改变时,执行函数
'currentUser.id' : function (newVal,oldVal) {
console.log(newVal);
console.log(oldVal);
},
//侦听路由的变化
//下面这种写法是错的,不能使用箭头函数,因为箭头函数没有this!!!!!
'$route.query.page':(newVal,oldVal)=>{
console.log(this);
}
},
//深度侦听对象【此时就不写成函数,而是写成对象的形式】
lists: {
handler(newVal, oldVal) { /* ... */ },
deep: true //当lists这个对象 变化,或者lists对象里面的某个值变化时,执行handler里的方法
},

指令v-

  • v-text:更新元素的 textContent
  • v-html:更新元素的 innerHTML
  • v-bind:动态地绑定一个或多个属性,或一个组件 prop 到表达式。
  • v-on:绑定事件监听器。
  • v-once:进入页面时 只渲染一次 之后即使数据变更也不再进行渲染

模板语法-指令:https://cn.vuejs.org/v2/guide/syntax.html

指令中,等号后面的冒号可以省略

1
2
3
4
5
6
7
<p v-bind:id="songId">...</p>
<p v-bind:id=songId>...</p>
<p :id=songId>...</p>
<p v-on:click="test">...</p>
<p v-on:click=test>...</p>
<p @click=test>...</p>

  • v-bind:xxx="yyy"表示:将这个元素的xxx属性和 Vue 实例data中的yyy保持一致【用于绑定class、id、等各种属性,支持js语法】
  • v-on:绑定用户事件函数
  • v-model:在表单控件上双向绑定数据
  • v-html:双大括号里的内容默认以text的显示呈现,想要转换成html标签想要用v-html指令

v-bind用于绑定属性

动态地绑定一个或多个特性,或一个组件 prop 到表达式。
模板语法-特性:https://cn.vuejs.org/v2/guide/syntax.html

绑定data里的imgSrc

1
2
3
HTML
<img v-bind:src="imgSrc">

内联字符串拼接

1
<img :src="'/path/to/images/' + fileName">


绑定data里的songUrl

1
2
3
HTML
<a v-bind:href="songUrl">...</a>


绑定多个属性api:v-bind

1
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>

1
2
//ES6中的省略写法
<div v-bind="{loginpartSeen, login, signup, isLogin}"></div>

<span v-bind:title="message">将这个元素的 title 属性和data中的message保持一致

1
2
3
4
5
6
7
HTML
<div id="app-2">
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>

1
2
3
4
5
6
7
8
JS
var app2 = new Vue({
el: '#app-2',
data: {
message: '页面加载于 ' + new Date().toLocaleString()
}
})

响应式修改:

1
app2.message = '新消息' //修改message的值

ps:

1
2
3
4
5
6
7
app2.$el
app2.$data
app2.$data.message
等同于
app2.message


使用 JavaScript 表达式
双大括号里的内容可以看成是一个JS表达式
只能包含单个表达式,判断语句请改成三元表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
HTML
{{ 1 + 1 }} // 2
{{ typeof 'hello' }} //string
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + songId"></div>
<div v-bind:id="`list-${songId}`"></div>

此外,支持window自身的全局变量,如 Math 和 Date

v-bind绑定样式

class与style绑定:https://cn.vuejs.org/v2/guide/class-and-style.html
菜鸟教程:样式绑定

v-bind:class绑定class

基础用法

1
<div :class="{active:clickIndex === index}"></div>

我们可以使用三元表达式来切换样式

1
2
3
4
5
<!-- 行间样式 -->
<div :style="mode===`edit`? '' : `width:260px;` "></div> //注意字符串要用反点号
<!-- 切换clss -->
<div :class=" isActive ? activeClass : '' "></div>

固定绑定class

1
<div :class="btnClass"></div>

1
2
3
data:{
btnClass:'btn active'
}

最终结果:<div class="btn active"></div>


除了固定绑定class,我们还可以通过设置true/false来动态切换class

对象语法绑定class

我们可以传给 v-bind:class 一个对象,以动态地切换 class,key为className,value为布尔值:

1
2
3
<div :class="{ active:isActive, btn-success:todoList.length }"></div>
只有当data里的isActive为true时才添加.active,只有当todoList的长度大于0时才添加.btn-success

1
2
3
data:{
isActive:true,
}

最终渲染成<div class="active"></div>

通过app.isActive = false可以动态切换


!注意
当中有横杠的class名要加单引号

1
2
3
<div class="static" //可以与普通类名共存
:class="{ active: isActive, 'text-danger': hasError }"> //text-danger要加单引号
</div>

1
2
3
4
data: {
isActive: true,
hasError: false
}

最终渲染为

1
<div class="static active"></div>

上面的写法过于臃肿,如果有多个class名,可以写到同一个对象中,这样就不需要一个个单独写class名了,直接写这个对象名就行了

1
2
3
<div class="static" //可以与普通类名共存
:class="classObject">
</div>

1
2
3
4
5
6
data: {
classObject: {
active: true,
'text-danger': false
}
}

单独添加一个class名

1
2
3
<div id="app">
<p :class="active">{{ message }}</p>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
active:{active:true} // 对象语法一般用于多个class名,单个class名推荐用下面的方法
}
})
等同于
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
active:'active', //单个class名推荐用这种方法
}
})

数组语法绑定class

1
<div :class="[activeClass, errorClass]"></div>
1
2
3
4
data: {
activeClass: 'active',
errorClass: 'text-danger'
}

最终渲染为<div class="active text-danger"></div>

三目运算

1
<div :class="[a ? b : c ,xxx]"></div>
1
2
3
data:{
xxx:'d'
}

当data中的a为真值时,渲染为<div class="b d"></div>

数组和对象语法混用绑定class

1
<div :class="[{ active: isActive }, errorClass]"></div>
1
2
3
4
data:{
isActive:true,
errorClass:'abc'
}

最终渲染为<div class="active abc"></div>

v-bind绑定内联样式style

  • 对象语法绑定style
1
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
1
2
3
4
data: {
activeColor: 'red',
fontSize: 30
}

如果有多个样式,直接绑定到一个对象通常更好,这会让模板更清晰:

1
2
3
4
5
6
data: {
styleObject: {
color: 'red',
fontSize: '13px' //驼峰式fontSize或者单引号'font-size'
}
}

1
<div :style="styleObject"></div>

各种写法

1
2
3
4
5
6
7
A. <p v-bind:class="className + '-container'">
B. <p v-bind:class=className + '-container'> × 【当中不能有空格】
B2. <p v-bind:class=className+'-container'>
C. <p v-bind:class="className + 'container'"> ×
D. <p v-bind:class="${className}-container"> ×
E. <p v-bind:class="`${className}-container`">
F. <p v-bind:class=`${className}-container`>

作业:
v-bind的作用,并分别写出v-bind的变量语法,数组语法,对象语法?

v-bind通常用来绑定属性的,格式是v-bind:属性名 = “值”,简写:属性名 = “值”
变量语法:v-bind:class = “变量”,变量形式 ,这里的变量的值,通常是在css定义好的类名
数组语法:v-bind:class= “[变量1,变量2]” ,数组形式,其实跟上面差不多,只不过可以同时绑定多个class名
对象语法:v-bind:class = {classname1:boolean,classname2:boolean},对象形式,这里的classname1(2)其实就是样式表中的类名,这里的boolean通常是一个变量,也可以是常量、计算属性等,这种方法也是绑定class最常用的方式。

v-on事件处理

绑定事件监听器

1
2
<button v-on:click="counter += 1">增加 1</button>
<p>这个按钮被点击了 {{ counter }} 次。</p>

查看在线例子

绑定用户事件函数
click时执行doSomething

1
2
3
HTML
<a v-on:click="doSomething">...</a>


<button v-on:click="reverseMessage">逆转消息</button> :click时执行reverseMessage函数

1
2
3
4
5
6
HTML
<div id="app-5">
<p>{{ message }}</p>
<button v-on:click="reverseMessage">逆转消息</button>
</div>

1
2
3
4
5
6
7
8
9
10
11
var app5 = new Vue({
el: '#app-5',
data: {
message: 'Hello Vue.js!'
},
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})

PS:

1
2
3
app5.message //获取message的值
app5.reverseMessage(); //执行reverseMessage

Vue的data里的内容和methods里的内容都会挂载到实例对象之下,所以可以直接this.messagethis.reverseMessage()


绑定多个方法

1
2
//ES6中的省略写法
<div v-on="{clickSaveBtn, print, clickLogout}"></div>


除了绑定事件,还能绑定属性值

1
2
3
4
5
6
HTML
<div id="app">
<p>{{ foo }}</p>
<button v-on:click="foo = 'baz'">Change it</button>
</div>

1
2
3
4
5
6
7
8
9
10
JS
var obj = {
foo: 'bar'
}
new Vue({
el: '#app',
data: obj
})

v-on绑定属性值

1
<p @click="show=!show">{{name}}</p>

修饰符

模板语法-指令-修饰符:https://cn.vuejs.org/v2/guide/syntax.html

修饰符 (Modifiers) 是以.指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。

  • .prevent 修饰符用于阻止浏览器默认行为event.preventDefault()
  • .stop修饰符用于阻止冒泡
  • .enter表示敲的是Enter键 @keyup.enter="xxx"

事件修饰符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- 阻止单击事件冒泡 -->
<a @click.stop="doThis"></a>
<!-- 提交表单时阻止刷新页面 -->
<!-- 注意!!!submit事件要加在form表单身上,而不是按钮上 -->
<form @submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a @click.stop.prevent="doThat"></a>
<!-- 只有修饰符,没有事件 -->
<form @submit.prevent></form>
<!-- 使用捕获模式,而不是冒泡模式 -->
<div @click.capture="doThis">...</div>
<!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
<div @click.self="console.log('父')">
<div @click="console.log('子')"></div>
</div>
<!-- click 事件只触发一次 -->
<a @click.once="doThis"></a>

按键修饰符

  • enter
  • tab
  • delete (捕获 “删除” 和 “退格” 键)
  • esc
  • space
  • up
  • down
  • left
  • right
  • ctrl
  • alt
  • shift
  • meta(windows键,就是那个’田’字键)
1
2
3
4
5
6
7
8
9
10
<!-- 只有在 keyCode 是 13 时调用方法 -->
<input @keyup.13="submit">
<!-- Enter 时调用方法 -->
<form @keyup.enter="onSubmit">...</form>
<!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>

你也可直接将 KeyboardEvent.key 暴露的任意有效按键名转换为 kebab-case 来作为修饰符:

1
2
3
<input @keyup.page-down="onPageDown">
PgDn按键的ev.key == PageDown,因此写成kebab-case形式

JS Bin

v-on多个事件

1
2
3
<div id="app">
<div v-on="{click:fnClick,mouseenter:fnEnter}">Yo.</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
var app = new Vue({
el: '#app',
methods: {
fnClick() {
console.log('clicked');
},
fnEnter() {
console.log('entered');
}
}
})

v-model表单控件双向绑定

普通html用name=’xxx’来传递数据
vue中用v-model替代name

v-model实际上是个语法糖:

1
2
3
4
5
6
<div id="app4">
{{price}}<br>
<input v-model="price">
<!-- 等同于 -->
<input :value="price" @input="price = $event.target.value">
</div>

1
2
3
4
5
6
new Vue({
el: '#app4',
data: {
price: '20'
}
});

v-model可用于:

  • input
  • textarea
  • select

普通input-text

<input v-model="message"> :将输入框里的值与data里的message双向绑定

1
2
3
4
5
6
HTML
<div id="app-6">
<p>{{ message }}</p>
<input v-model="message">
</div>

1
2
3
4
5
6
var app6 = new Vue({
el: '#app-6',
data: {
message: 'Hello Vue!'
}
})

单选⊙和多选框□

菜鸟教程:单选修改颜色

一个简单的单选例子:

1
2
3
4
5
6
<div id="app">
香蕉<input type="radio" v-model="fruit" value="香蕉"><br>
苹果<input type="radio" v-model="fruit" value="苹果"><br>
桃子<input type="radio" v-model="fruit" value="桃子"><br>
我最爱吃的水果:{{fruit}}
</div>

1
2
3
4
5
6
const app = new Vue({
el:'#app',
data:{
fruit:'' //单选用字符串,多选框用数组
}
})

JS Bin

一个简单的多选框例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="app">
<input type="radio" v-model="gender" value="male">
<input type="radio" v-model="gender" value="female">
<br>我的性别是:{{gender}}
<hr>
西瓜<input type="checkbox" v-model="fruits" value="melon">
苹果<input type="checkbox" v-model="fruits" value="apple">
香蕉<input type="checkbox" v-model="fruits" value="banana">
桃子<input type="checkbox" v-model="fruits" value="peach">
我爱吃:{{fruits}}
</div>

1
2
3
4
5
6
7
8
var app = new Vue({
el: '#app',
data: {
gender: 'male', //默认值,单选用字符串
fruits: ['melon', 'peach'] //默认值,多选用数组
}
})

checkbox

在checkbox中,v-model双向绑定多选框的勾选状态

1
<input type="checkbox" v-model="todo.done">

【点击查看例子】


全选与取消全选:https://c.runoob.com/codedemo/3870

select

1
2
3
4
5
6
7
8
9
10
11
<div id="app">
<select v-model="city">
<!-- 推荐像下面这样提供一个value为空的禁用选项。 -->
<option disabled value="">请选择</option>
<option value="sh">上海</option>
<option value="bj">北京</option>
<option value="gz">广州</option>
<option value="sz">深圳</option>
</select>
app.city={{city}}
</div>
1
2
3
4
5
6
var app = new Vue({
el:'#app',
data:{
city:'bj',//默认值
},
})

v-model的修饰符

  • v-model.lazy :v-model默认实时监听数据的变化,添加lazy修饰符后,只有当blur或者按下Enter时才变更数据
  • v-model.trim:去除输入框前后空格
  • v-model.number

v-model.lazy

1
<input type="text" v-model.lazy="userName">

v-model,当在输入框输入内容时,实时动态更新数据
添加修饰符.lazy之后,只有当blur或按下Enter键时才更新数据
应用场景:表单验证时,用户一个字一个字输入时,我们不需要实时验证,等到用户把内容输入完后再验证用户信息
JS Bin

v-model.trim去除前后空格

1
<input type="text" v-model.trim="userName">

v-model.number转成数字

1
<input type="text" v-model.number="price">

输入框里的内容是字符串形式,如果后期需要对输入框里的值进行加减乘除运算,需要parseInt
通过v-model.number可以简化上述操作,直接将字符串数字转成数字类型

v-html

v-html:更新元素的innerHTML
语法:<p v-html="xxx"></p> 或者自闭合 <p v-html="xxx" />
文档:模板语法-原始HTML

将data里的rawHtml以html标签的形式呈现

1
2
3
4
5
6
7
HTML
<p>以text形式呈现: {{ rawHtml }}</p>
<p>转换成html标签: <span v-html="rawHtml"></span></p>
//或者写成自闭和的形式
<span v-html="rawHtml" />

!!你的站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户在input中输入的内容使用v-html。

v-text:更新元素的 textContent
其实,双花括号就是v-text的语法糖

1
2
3
<p>{{msg}}</p>
等同于
<p v-text="msg"></p>

条件渲染与循环渲染

  • v-if:true时插入DOM,false时从DOM中删除【对比v-show,true时显示,false时隐藏】
  • v-for:绑定数组里的数据来渲染一个项目列表

v-if条件渲染

用于动态在DOM内添加或删除DOM元素
注意,v-if会复用已有元素,如果不想复用,需要添加唯一的key
<p v-if="true">我被插入到DOM中</p>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
HTML
<div id="app-3">
//根据seen的true或false来改变p的插入/移除
<p v-if="seen">现在你看到我了</p>
<!-- 渲染后template标签消失 -->
<template v-if="seen">
<h1>菜鸟教程</h1>
<p>学的不仅是技术,更是梦想!</p>
<p>哈哈哈,打字辛苦啊!!!</p>
</template>
</div>

1
2
3
4
5
6
7
8
9
10
11
JS
var app3 = new Vue({
el: '#app-3',
data: {
seen: true
}
})
输入 app3.seen = false
可以看到p标签被移除了

菜鸟教程:v-if

Vue 在插入/更新/移除元素时自动应用过渡效果

v-if搭配template标签使用

1
2
3
4
5
6
7
8
9
10
<div id="app">
<p v-if="Seen">你看得见我吗?</p>
</div>
等同于
<div id="app">
<template v-if="Seen">
<p>你看得见我吗?</p>
</template>
</div>

当Seen为true时,template包含的内容会被渲染出来(template标签本身不会渲染)
template只能和v-if搭配,不能和v-show搭配!

v-if,v-if-else,v-else

https://cn.vuejs.org/v2/guide/conditional.html#v-else-if

为了防止复用原有元素,需要指定唯一的key

1
2
3
4
5
<div id="app">
<div v-if="people===`admin` || people===`super_admin`" key="admin">你好,管理员</div>
<div v-else-if="people===`hr`" key="hr">你好,hr</div>
<div v-else key="user">你好,用户</div>
</div>

1
2
3
4
5
6
var app = new Vue({
el:'#app',
data:{
people:'admin',
}
})

1
2
3
4
5
6
7
8
<div id="app">
<div v-if="Math.random() > 0.5">
Sorry
</div>
<div v-else>
Not sorry
</div>
</div>
1
2
3
new Vue({
el: '#app'
})

菜鸟教程:v-else

v-for列表渲染

绑定数组里的数据来渲染一个项目列表
<li v-for="todo in todos">

1
2
3
4
5
6
7
8
9
HTML
<div id="app-4">
<ol>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ol>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
JS
var app4 = new Vue({
el: '#app-4',
data: {
todos: [
{ text: '学习 JavaScript' },
{ text: '学习 Vue' },
{ text: '整个牛项目' }
],
}
})

数组的响应式变更

数组的更改
响应式修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//直接改变原始数组
app4.todos.push( { text: '新项目' } );//数组最后添加一个新项目
app4.todos.pop() //抛出去最后一项
app4.todos.shift() //删除数组中的第一项
app4.todos.unshift( {text:'xxx'} ) //在数组最前面添加一项
万能的.splice(起点,个数,插入值)
app4.todos.splice(2,1) //从第2项开始,删除1项
app4.todos.splice(2,0,{ text:'xxx' }) //从第2项开始,删除0项,在第2为前面插入{text:'xxx'}
app4.todos.sort((a,b)=>a-b)
appe.todos.reverse()
//不会直接改变原始数组,需要手动进行替换
app4.todos = app4.todos.filter(?)
app4.todos = app4.todos.concat(?)
app4.todos = app4.todos.slice(?)

无法响应式修改:

1
2
3
4
5
6
app4.todos[0] = 123; //视图没有重新渲染
app4.todos.length = 1; //视图没有重新渲染
//解决方法:数组用万能的splice
app4.todos.splice(0,1,123) //将第0项删除后替换成123
app4.todos.splice(1) //只保留第一项

或者用this.$set(this.arr, index, newValue)https://cn.vuejs.org/v2/guide/list.html#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9

1
2
3
4
5
6
7
8
9
10
11
new Vue({
el:'#app',
data:{
todos:[0,1,2,3,4]
},
methods:{
change(){
this.$set(this.todos,1,'改变了')
}
}
})

【点击查看例子】


v-for配合函数运算

1
2
3
4
5
6
<div id="app">
<ul>
//此处配合三元运算
<li v-for="food in foods">{{food.name}}: ${{food.discount?food.price * food.discount:food.price}}</li>
</ul>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var app = new Vue({
el: '#app',
data: {
foods: [{
name: '葱',
price: 10,
discount: 0.5
},
{
name: '姜',
price: 5,
discount: 0.45
},
{
name: '蒜',
price: 8
},
]
}
})

可以通过app.foods.push({name:'辣椒',price:3,discount:.4})进行添加

v-for数组渲染与对象渲染

1
2
3
4
5
//数组
<div v-for="(item, index) in items"></div>
//对象
<div v-for="(val, key, index) in object"></div>

v-for迭代对象

菜鸟教程:v-for

1
<li v-for="value in obj">
1
2
3
4
5
6
7
8
9
10
new Vue({
el: '#app',
data: {
obj: {
name: '菜鸟教程',
url: 'http://www.runoob.com',
slogan: '学的不仅是技术,更是梦想!'
}
}
})

最后会将obj里的所有value渲染出来:查看在线例子

v-for迭代整数

1
2
3
<li v-for="n in 10">
{{ n }}
</li>
1
2
3
new Vue({
el: '#app'
})

查看在线例子

v-cloak

由于css先加载,vue后加载,所以双括号一开始会闪现;
解决办法:添加v-cloak,然后设置css。当vue加载完成后,这个v-cloak就会自动删除

1
2
3
<div id="app" v-cloak>
{{大胡子}}
</div>
1
2
3
[v-cloak]{
display: none !important;
}

这样一来,双括号就不会闪现了

结合v-if和loading动画

v-cloak可以不显示双花括号,但是会留白,此时用v-if配合loading动画

1
2
3
4
5
6
<div id="app" v-cloak>
<div v-if="msg">
{{ msg }}
</div>
<div v-else>loading.......</div>
</div>

v-cloak起到不显示双花括号的功能,v-if在生命周期获得msg后才显示页面内容,负责显示loading

缩写(v-bind与v-on)

1
2
3
4
5
6
7
8
9
10
11
<a v-bind:href="songUrl">...</a>
v-bind:缩写成冒号:
<a :href="songUrl">...</a>
------------------
<a v-on:click="doSomething">...</a>
v-on:xxx缩写成@xxx
<a @click="doSomething">...</a>

组件component

组件系统是 Vue 的一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。
在一个大型应用中,有必要将整个应用程序划分为组件,以使开发更易管理。
组件用于提高代码的复用性,便于开发和维护。
组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用 is 特性进行了扩展的原生 HTML 元素。所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。

组件的注册(组件的作用域)

全局组件

将组件的template写到html里,然后在组件里传选择器


局部组件

父子组件通信

父组件将数据传给子组件的props
子组件无法直接修改父组件的数据,必须通过$emit()托付父组件,让父组件帮忙修改父组件的数据
123.png

1
2
<hello :xxx="name" @myfn="name='hello world!' + $event"><hello>
//点击后,name变成hello world
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var hello = {
props:['xxx'],
template:`<h1 @click="$emit('myfn',参数)">{{xxx}}</h1>`,
};
var app = new Vue({
el:'#app',
components:{
hello,
},
data:{
name:'stage',
},
})

组件绑定原生事件

在 Vue 2.0 中,为自定义组件绑定原生事件必须使用 .native 修饰符:

1
<my-component @click.native="handleClick">Click Me</my-component>

.sync 修饰符

在有些情况下,我们可能需要对一个 prop 进行“双向绑定”,使子组件的prop修改时,父组件的data也跟着改变。为了方便起见,我们为这种模式提供一个缩写,即 .sync 修饰符,其实它是v-on:update的语法糖

1
2
3
4
Vue.component('child-say',{
props:['msg'],
template:`<button @click="$emit('update:msg','儿子的值')">儿子改变父亲的data</button>`,
});

1
2
3
4
<text-document
:msg="msg"
v-on:update:msg="msg = $event"
></text-document>

上面的代码用.sync语法糖改写如下:

1
<child-say :msg.sync="msg"></child-say>

【点击查看例子】

动态组件

https://cn.vuejs.org/v2/guide/components.html#%E5%8A%A8%E6%80%81%E7%BB%84%E4%BB%B6
Vue内置了一个component标签,依:is="组件名"的值,来决定哪个组件被渲染。

1
<component :is="cpName"></component>

JS Bin

在动态组件上使用 keep-alive

https://cn.vuejs.org/v2/guide/components-dynamic-async.html#%E5%9C%A8%E5%8A%A8%E6%80%81%E7%BB%84%E4%BB%B6%E4%B8%8A%E4%BD%BF%E7%94%A8-keep-alive

1
2
3
4
<!-- 失活的组件将会被缓存!-->
<keep-alive>
<component :is="cpName"></component>
</keep-alive>

异步组件(按需加载,懒加载)

文档:异步组件

如果一开始打开页面加载所有的组件,加载起来比较耗时,我们可以把一些组件定义为异步组件,在需要使用的时候再加载。

优点:

  • 按需加载,可以节省首次加载的时间,提高页面打开的速度
  • 第一次按需加载完成之后,会被缓存下来,再次使用这个组件时就不会重复加载了

默认情况下,webpack会把所有组件打包在一个js文件里,导致js文件过大;异步组件可以打包成独立的js文件,并且只有在这个组件需要被渲染的时候(比如 v-if 触发渲染)才会触发

1
2
3
4
5
6
7
<!-- 一开始seen为false,页面中没有渲染该组件
点击后,页面渲染该组件,于是异步加载
-->
<change-skin
v-if="seen"
@click="seen = !seen">
</change-skin>

1
2
3
4
5
6
7
const ChangeSkin = () => import(/* webpackChunkName: "change_skin" */ './ChangeSkin.vue');
new Vue({
components: {
ChangeSkin,
'my-component': () => import('./my-component')
}
})

解析 DOM 模板时的注意事项

https://cn.vuejs.org/v2/guide/components.html#%E8%A7%A3%E6%9E%90-DOM-%E6%A8%A1%E6%9D%BF%E6%97%B6%E7%9A%84%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9

有些 HTML 元素,诸如 ul、ol、table 和 select,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 li、tr 和 option,只能出现在其它某些特定的元素内部。

1
2
3
4
5
6
7
8
<ul>
<blog-post-row></blog-post-row>
</ul>
这个自定义组件 <blog-post-row> 会被HTML视作无效的内容提升到外部,导致最终渲染结果出错,变成
<blog-post-row></blog-post-row>
<ul></ul>

如果想让这个组件插入ul的内部,就要使用is属性

1
2
3
<ul>
<li is="blog-post-row"></li>
</ul>

过滤器

1
2
3
4
5
<!-- 在两个大括号中 -->
{{ message | capitalize }}
<!-- 在 v-bind 指令中 -->
<div v-bind:id="rawId | formatId"></div>

文档:【过滤器】
语法:

1
2
3
<div>
{{ message | xxx('参数1', 参数2) }}
</div>

默认第一个参数value是管道符前面的值,剩下的参数是人为传入的其他参数

1
2
3
4
filters: {
xxx(value,参数1,参数2) {
return value + 参数1 + 参数2;
},

过滤器一般用于处理文本的格式化,比如将data里的name变成大写,将data里的长度变成米,将data里的价格后面添上“元”等。又比如,过滤出todoLists里的所有、已完成、未完成 过滤器不会修改data里的值,只用于将data里的值格式化后渲染出来。
过滤器由“管道”符号|表示:

1
2
3
4
5
6
7
8
<div id="app">
<input type="text" v-model.number="length">毫米
<p>{{ length | meter }}</p>
<hr>
<p>{{ money | country('人民币') }}</p>
</div>

Vue.filter(‘过滤器名称’, (管道前面的值,自定义传的值)={});

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//在new Vue之前,注册一个全局过滤器
Vue.filter('meter', (value)=> {//第一个参数value就是meter的值
return value/1000 + '米';
});
Vue.filter('country', (value,xxx)=> {//第一个参数value就是country的值,第二个参数xxx是传入的参数'人民币'
return value + xxx;
});
new Vue({
el:'#app',
data:{
length:0,
money:10,
},
});

除了全局过滤器,还可以用局部过滤器

1
2
3
4
5
6
7
8
9
10
11
12
//局部过滤器
new Vue({
el:'#app',
filters: {
meter(value) {
return value/1000 + '米';
},
country(value,xxx) {
return value + xxx;
}
}
});

  • 除了双括号里可以用过滤器外,v-bind也可以
1
<div :id="length | meter"><div>

简单的数据格式化可以用filter,如果是复杂的数据格式化推荐用计算属性,因为计算属性本身带有缓存。

自定义指令

自定义指令用于对普通 DOM 元素的复杂操作进行封装(比如元素的拖拽)。
文档:【自定义指令】

全局指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Vue.directive('pin',(el,binding)=>{
//console.dir(binding)
let pinned = binding.value;//等号右边的值
let position = binding.modifiers;//修饰符,{bottom:true,right:true}
let type = binding.arg;//传参,'error'
if(pinned){
el.style.position='fixed';
for(key in position){
el.style[key]='20px';
}
if(type=='error'){
el.style.background='red';
}
}else{
el.style.position='static';
el.style.background='#ccc';
}
});
new Vue({
el:'#app',
data:{
pinned:false,
},
});
1
2
3
4
5
<div id="app">
<div class="card" v-pin:error.bottom.right="pinned">
<button @click="pinned=!pinned">钉住/取消</button>
</div>
</div>

【点击查看例子】

局部指令

除了全局指令,我们也可以注册局部指令

1
2
3
4
5
6
7
new Vue({
directives: {
pin(el,binding){
//doSomething
}
}
})

一个最简单的例子:

1
2
3
4
5
6
7
8
9
10
new Vue({
el:'#app',
directives: {
focus:{
inserted(el){
el.focus();
}
}
}
})

1
<input type="text" v-focus>

JS Bin

另一个例子:
一个最简单的例子:

1
2
3
4
5
6
7
8
9
10
new Vue({
el:'#app',
directives:{
focus(el,binding){
if (binding.value) { //binding.value,即等号后面的计算结果
el.focus();
}
}
},
})

当todoList的长度大于0时,才触发指令

1
<input type="text" v-focus="todoList.length">

对象字面量

如果指令需要多个值,可以传入一个 JavaScript 对象字面量。记住,指令函数能够接受所有合法的 JavaScript 表达式。

1
<div v-demo="{ color: 'white', text: 'hello!' }"></div>

1
2
3
4
Vue.directive('demo', (el, binding) => {
console.log(binding.value.color) // => "white"
console.log(binding.value.text) // => "hello!"
})

钩子函数

钩子函数的用法

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  • inserted:被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)
  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
  • unbind:只调用一次,指令与元素解绑时调用。

钩子函数参数

https://cn.vuejs.org/v2/guide/custom-directive.html#%E9%92%A9%E5%AD%90%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0

1
2
<div v-demo:foo.a.b="msg"></div>
<!-- msg的值为'hello' -->
1
2
3
4
5
6
el // <div></div> 指令绑定的DOM元素
binding.name //demo
binding.value //hello
binding.expression //msg
binding.arg //foo 传给指令的参数
binding.modifiers //{a:true, b:true} 是否传入修饰符a,b

自定义指令实现拖拽

关于用自定义指令在vue中实现元素拖动
拖拽原理图
JS Bin

mixins混入(复用)

new Vue({options})里的options提取出来,从而使相同option得到复用

混入 (mixins) 是一种分发 Vue 组件中可复用功能的非常灵活的方式。
文档:【混入】

1
2
3
4
<div id="app">
<button @click="yellow">{{msg}}</button>
<vue-hello></vue-hello>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//定义要复用的混入
var mixin = {
data(){
return {
msg:'hello world!',
}
},
methods:{
yellow(ev){
ev.target.style.background='yellow';
},
},
};
Vue.component('vue-hello',{
mixins:[mixin],
template:`<p @click="yellow">{{msg}}</p>`,
});
new Vue({
el:'#app',
//以数组的形式传入混用
mixins: [mixin],
})

【点击查看例子】

!注意:当混入的数据和组件原有的数据重名时,以组件数据优先。

插件

在utils文件夹下,新建util.js

1
2
3
4
5
6
7
8
9
10
11
12
13
import axios from 'axios';
function formatDate(date){
.........
}
export default {
install(Vue, options) {
//添加到Vue原型上
Vue.prototype.$formatDate = formatDate;
Vue.prototype.$axios = axios;
}
}

然后在main.js中使用它:

1
2
import Util 'utils/util.js';
Vue.use(Util);

组件插槽

插槽用于内容的分发。 将 <slot> 元素作为承载分发内容的出口。
文档:【插槽】

单个插槽

一个最简单的例子:

1
2
3
4
5
6
7
Vue.component('alert-box', {
template: `
<div>
<slot>如果没有内容,我将作为默认内容显示;如果有内容,我将被分发的内容直接替换</slot>
</div>
`
})

1
2
3
<alert-box>
<h3>自定义内容</h3>
</alert-box>

当组件渲染的时候,这个 slot 标签将会被替换为<h3>自定义内容</h3>

最终渲染成:

1
2
3
<div>
<h3>自定义内容</h3>
</div>

多个插槽,取个名字

有些时候我们需要多个插槽,这时可以给这些slot取个名字

1
2
3
4
5
6
7
8
9
10
<div id="app">
<vue-card>
<h2 slot="title">标题</h2>
<template slot="content">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</template>
<p slot="more">更多信息</p>
</vue-card>
<!-- 如果不传内容,将会显示slot的默认值 -->
<vue-card></vue-card>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//组件
Vue.component('vue-card',{
template:`
<div class="card">
<div>
<slot name="title">显示默认标题</slot>
</div>
<div>
<slot name="content">显示默认内容</slot>
</div>
<div>
<slot name="more">显示默认更多</slot>
</div>
</div>
`
})

【点击查看例子】

作用域插槽

作用域插槽

用途:从子组件的slot中获取数据

1
2
3
4
5
6
7
8
9
10
11
Vue.component('cp',{
template:`<div>
<slot :msg="msg" :count="count"></slot>
</div>`,
data(){
return {
msg:'子组件的内容',
count:10
}
}
});

通过slot-scope="slotProps"获取子组件的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="app">
<cp>
<h2 slot-scope="xxx">
{{xxx.msg}} --- {{xxx.count}}
</h2>
</cp>
</div>
<!-- 利用ES6解构赋值精简 -->
<div id="app">
<cp>
<h2 slot-scope="{msg,count}">
{{msg}} --- {{count}}
</h2>
</cp>
</div>

JS Bin

访问插槽

通过this.$slots.插槽名[0]来访问插槽

1
2
3
4
5
6
7
8
9
Vue.component('cp',{
template:`<div>
<slot name="a"></slot>
</div>`,
mounted(){
console.log(this.$slots.a[0]);
console.log(this.$slots.a[0].elm.innerText)
}
});

JS Bin

ref注册引用

api:ref
ref被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,ref指向的就是 DOM 元素;如果用在子组件上,ref就指向组件实例:

1
2
<!-- `this.$refs.xx` 指向这个DOM节点 -->
<p @click="yy" ref="xx">Hello World!</p>

1
2
3
4
5
6
7
8
9
new Vue({
el:'#app',
methods:{
yy(){
//this.$refs.xx
this.$refs['xx'].style.color='red';
}
}
})

【点击查看例子】
注册单个元素时,相当于querySelector()

在v-for中要有下标[0],因为$refs是个数组

1
<p v-for="(list,i) in lists" :ref="i"></p>

1
this.$refs['i'][0].style.color='red';

注册多个元素时,相当于querySelectorAll()

过渡&动画

在下列情形中,可以添加transition组件

  • v-show
  • v-if
  • 动态组件
  • 组件根节点
1
2
3
4
5
6
7
8
<div id="app">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="test">
<p v-show="show">hola</p>
</transition>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
p{
width:100px;
background: red;
}
@keyframes bounce {
0%{transform:scale(0)}
50%{transform:scale(1.5)}
100%{transform:scale(1)}
}
.test-enter-active{
animation:bounce .5s;
}
.test-leave-active{
animation:bounce 2s reverse;
}

【点击查看例子】

vue的响应式更改

数组的更新

数组更新检测

由于 JavaScript 的限制,Vue 不能检测以下变动的数组:

  1. 当你利用索引直接设置一个项时,例如:this.items[index] = newValue
  2. 当你修改数组的长度时,例如:this.items.length = newLength
1
2
3
4
5
6
7
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的

为了解决第一类问题,可以用以下两种方式,达到响应式更改

1
2
3
4
5
6
7
// Vue.set
this.$set(this.todos, index, newValue)
或者
// 万能的splice
this.todos.splice(index, 1, newValue)

【点击查看例子】

为了解决第二类问题,你可以使用 splice:

1
this.todos.splice(newLength)

对象的更新

对象更改检测

深入响应式原理

还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:

1
2
3
4
5
6
7
8
9
var vm = new Vue({
data: {
user:{name:'stage'}
}
})
// `vm.user.name` 现在是响应式的
vm.user.age = 22//设置新值
// `vm.user.age` 不是响应式的

可以使用 Vue.set(obj, key, value)来解决这个问题

1
this.$set(this.messageObj, 'age', 22)

【点击查看例子】

另外,你也可以使用Object.assign,但是要注意

1
2
3
4
5
6
7
8
9
10
11
12
//不要写成这样!!!
Object.assign(vm.user, {
age: 22,
favoriteColor: 'Vue Green'
})
//建议写成这样!!!!
vm.user = Object.assign({}, vm.user, {
age: 22,
favoriteColor: 'Vue Green'
})

VUE的练习题

1
2
3
4
5
<div id="app">
<span ____填空______>
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
1
2
3
4
5
6
var app = new Vue({
el: '#app',
data: {
message: '提示信息'
}
})

答案:

1
2
3
4
5
6
7
8
9
10
11
v-bind:title="message"
v-bind:title='message'
v-bind:title=message
其中,message===this.message
v-bind:title="this.message"
v-bind:title='this.message'
v-bind:title=this.message
//以下是错误的!!!!!!
v-bind:title="{{message}}" //双引号中不能出现{{}}符号

补充

  • Vue的data里的内容和methods里的内容都会挂载到实例对象之下,所以可以直接this.messagethis.reverseMessage()

  • computed 对象内的方法如果在初始化时绑定到元素上的事件会先执行一次这个方法 ,而 methods 内的方法则不会;

1
2
3
<div id="app">
{{x}}
</div>
1
2
3
4
5
6
7
8
new Vue({
el: '#app',
computed:{
x(){
alert(1);
}
},
})

进入页面时会自动执行computed里的方法

设置图片的默认值

通过表达式||,当imgUrl为假值时,显示默认图片

1
<img :src="imgUrl || defaultImg">

vue中引入图片

在html中

1
<img src="@/assets/imgs/xxx.png">

这种方式是按照正常HTML语法引用路径

在js中

1
2
3
4
5
6
7
8
import avatar from '@/assets/logo.png'
//然后在data里定义
data(){
return {
avatar
}
}

接着就可以在html里绑定 <img :src="avatar" />

通过require引入图片

1
avatar:require("@/assets/xxx.png")

通过require可以实现动态设置图片

1
user.set('avatar',require(`imgs/${Math.floor(Math.random()*14)}.png`));

踩坑

methods的方法名不能叫do

1
<button @click="do">点我</button>
1
2
3
4
5
6
7
8
new Vue({
el:'#app',
methods:{
do(){
console.log(1);
}
},
})

方法名叫do会报错

methods的方法名不能叫delete

1
<button @click="delete">删除</button>

方法名叫delete会报错

初始值为null时

如果数据的初始值是null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
data:{
list:null
}
```
那么在渲染`list.xxx`时会报错`cannot find xxx of null`
解决方法:
给最外层加上`<div v-if="list != null"></div>`
## v-for和v-if需要唯一的key
如果用到了v-for或者v-if,你们必须加上唯一的key,以免就地复用
```html
<div id="app">
<button @click="show=!show">click</button>
<br>
<input style="background:red;" type="text" v-if="show">
<input type="text" v-else>
</div>

上述代码不加key,那么在input输入内容后,切换另一个input会被复用

添加上唯一的key,可解决该问题

1
2
3
4
5
6
<div id="app">
<button @click="show=!show">click</button>
<br>
<input style="background:red;" type="text" v-if="show" key="txt1">
<input type="text" v-else key="txt2">
</div>

【点击查看例子】

数组与对象的更新

数组的更新

1
2
3
4
5
6
7
8
9
10
11
12
//在Vue中,以下操作无法更新视图
this.arr[index] = newVal;
this.arr.length = 2;
//要改变arr[index]必须使用如下方法
this.$set(this.arr, index, newVal)
或者
this.arr.splice(index, 1, newVal)
//要改变arr的length,必须使用
this.arr.splice(newLength)

对象的更新

在遍历对象时,是按 Object.keys() 的结果遍历,因此obj格式的数据可能在不同的 JavaScript 引擎下渲染出来的顺序不一致。

对象的更新方法:

1
2
3
4
this.$set(this.obj, 'age', 27)
或者
this.obj = Object.assign({}, this.obj, {age:27})

-------------本文结束感谢您的阅读-------------