引包
CDN:<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
下载:https://cn.vuejs.org/js/vue.js
初始化
Vue通过new来初始化实例
let vm = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
声明式渲染
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:数据驱动视图
<body>
<div id="app"> <!-- 3.html写出el的绑定元素,默认app -->
{{msg}} <!-- 6.实例中的对象通过插值表达式{{ }}渲染到html中 -->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: { //data存放实例中的数据
msg: 'Hello Vue!',
msg2: 'Content'
},
methods: { //methods存放声明的方法
getContent() {
return this.msg + ' ' + this.data;//通过this来引用实例抛出的属性
}
}
})
</script>
</body>
{{ }} 插值表达式内的数据类型
<h2>{{msg}}</h2>
<!--插入vue属性 Hello Vue! -->
<h3>{{ 2 }}</h3>
<!--插入数字 2 -->
<h3>{{ 'hello' }}</h3>
<!--插入字符串 Hello -->
<h3>{{ {id:1} }}</h3>
<!--插入对象 { "id": 1 } -->
<h3>{{ 1>2 ? '真的':'假的' }}</h3>
<!--插入三元运算 假的 -->
<h3>{{ msg.split('').reverse().join('') }}</h3>
<!--插入js方法 !euV olleH -->
<h3>{{ getContent() }}</h3>
<!--插入函数 Hello Vue! Content -->
v-text & v-html 指令
向html内添加文本还有两个方法 v-text 和 v-html ,在标签内写入 v-text='属性' 就可以向标签中间插入属性的值,而 v-html 的作用则是可以同时插入html标签渲染到页面中,类似于js的 innerText 和 innerHTML
{{}} 和 v-text的作用是一样的,都是插值直接渲染
v-html 则是既能插入值又能插入标签
<h2 v-text='msg'></h2> <!-- Hello Vue! -->
//-------------------------------------------
htmlMsg:'<h3>Max</h3>'
<h2 v-html='htmlMsg'></h2> <!-- Max -->
v-show & v-if 指令
vue中的条件渲染,分为 v-show 和 v-if v-else-if v-else 两个
v-show 通过属性的布尔值来进行判断是否显示,为false则渲染到页面后通过行内 display: none 隐藏
isShow:true,
<div v-show = 'isShow'>显示</div> //---显示 <div>显示</div>
//-------------------------------
isShow:false,
<div v-show = 'isShow'>显示</div> //---不显示 <div style="display: none;">显示</div>
v-if 则是判断真实的是否渲染到html,是“真正”的条件渲染,如果是false,则不会在html内渲染
isRender:true,
<div v-if = 'isRender'>
显示
</div>//渲染 <div>显示</div>
//-------------------------------
isRender:false,
<div v-if = 'isRender'>
显示
</div>//不渲染
v-else-if则是提供了不符合 v-if 条件之后的判断的方法,在标签内进行判断返回布尔值,v-else-if可以进行多层判断,如果以上条件均不满足,则显示 v-else ,需要注意的是 v-else 不写条件判断
<div v-if='num > 5'>num大于5</div>
<div v-else-if='5 > num'>num小于5</div>
<div v-else>num不是数字</div>
//-------------------------------------------
num:6 → <div>num大于5</div>
num:2 → <div>num小于5</div>
num:'字符串' <div>num不是数字</div>
选择使用 v-show 还是 v-if 要看具体适用情况
v-show:
- 初始化就被渲染到了html内,有更高的初始渲染开销
- 通过css来控制是否显示块,切换开销较小,状态经常改变,推荐使用
v-showv-if:
- 初始化时条件判断为false则不会渲染到html内,直到变为true才会开始渲染块
- 通过条件判断渲染和销毁块,有更高的切换开销,状态很少改变,则推荐使用
v-if
v-bind 指令
vue中通过 v-bind 通过返回的数据给标签添加属性
src:'./img/logo.png'
<div class="box" v-bind:src='src'></div>
如果需要给标签动态的添加或删除属性,需要在属性内写一个对象 { 需要添加的属性:vue声明的属性} 通过修改vue声明属性的布尔值来添加或删除该属性
<div class="box" v-bind:class='{ active:isActive }'></div>
//-----------------------------------------------------------
isActive:true
<div class="box active"></div>
isActive:false
<div class="box"></div>
{ 需要添加的属性:vue声明的属性} 还有一个使用方法是,需要给标签绑的一个属性绑定多个实例中的属性
<h4 v-bind:style='{color:color,fontSize:fontsize+"px"}'>小标题</h4>
v-bind 指令可以简写为 : 单独写在标签属性前面,例如 :class :src :title
v-on 事件处理指令
vue提供了 v-on 来绑定事件触发操作,'' 内可直接写一些简单的表达式
num: 0
<h3>{{ num }}</h3>
<button v-on:click='num+=1'>+1</button>
当整个事件的逻辑变得复杂了,需要以事件名的方式引入
<button v-on:click='plusOne'>+1</button>
methords:{
plusOne(){
this.num+=1;
}
}
结合 v-bind 指令,可以完成点击后更改属性的布尔值,来动态的更改属性的添加和删除
<div class="box" v-bind:class='{active:isActive}'></div>
<button v-on:click='changeColor'>改变颜色</button>
methods: {
changeColor() {
this.isActive = true;
this.isActive = !this.isActive;//可以通过!取反来实现点击反复切换
}
}
v-on 指令可以简写为 @ 单独写在标签属性前面,例如 @click @mouseover @focus
事件修饰符
修饰符是由点开头的指令后缀来表示的。
- .stop 是阻止冒泡行为,不让当前元素的事件继续往外触发,如阻止点击div内部事件,触发div事件
- .prevent 是阻止事件本身行为,如阻止超链接的点击跳转,form表单的点击提交
- .self 是只有是自己触发的自己才会执行,如果接受到内部的冒泡事件传递信号触发,会忽略掉这个信号
- .capture 是改变js默认的事件机制,默认是冒泡,capture功能是将冒泡改为倾听模式
- .once 是将事件设置为只执行一次,如 .click.once 代表只允许事件执行一次
- .passive 滚动事件的默认行为 (即滚动行为) 将会立即触发,而不会等待 onScroll 完成,这个修饰符尤其能够提升移动端的性能
<button v-on:click.once='plusOne'>+1</button> <!-- 点击事件将只会触发一次 -->
<form v-on:submit.prevent='onSubmit'></form> <!-- 提交表单不再重载页面 -->
<a v-on:click.stop.prevent="doThat"></a> <!-- 修饰符可以串联 -->
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
按键修饰符
在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:
<!-- 只有在 key 是 Enter 时调用 vm.submit() -->
<input v-on:keyup.enter="submit">
<!-- 处理函数只会在 $event.key 等于 PageDown 时被调用-->
<input v-on:keyup.page-down="onPageDown">
为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:
.enter.tab.delete(捕获“删除”和“退格”键).esc.space.up.down.left.right
你还可以通过全局 config.keyCodes 对象自定义按键修饰符别名:
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
为什么在 HTML 中监听事件?
v-on 这种事件监听的方式违背了关注点分离 (separation of concern) 这个长期以来的优良传统。但不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。
使用 v-on 有几个好处:
-
扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
-
无须在 JavaScript 里手动绑定事件,ViewModel 代码可以是非常纯粹的逻辑,和DOM完全解耦,易于测试
-
当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除,你无须担心如何清理它们
v-for 列表渲染指令
用 v-for 指令基于一个数组来渲染一个列表,v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名,可以随意命名
<div id="app">
<ul>
<li v-for='item in menus'>
<h3>序号:{{item.id}} - 名字:{{item.name}}</h3>
</li>
</ul>
</div>
<script src="./vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
menus:[
{id:1,name:'Zhang'},
{id:1,name:'Lee'},
{id:1,name:'Wang'},
{id:1,name:'Zhao'}
]
}
})
</script>
- 学号:1 - 名字:Zhang
- 学号:2 - 名字:Lee
- 学号:3 - 名字:Wang
- 学号:4 - 名字:Zhao
在 v-for 中,还可以访问组件内的所有属性,v-for 还支持一个可选的第二个参数,即当前项的索引
<div id="app">
<ul>
<li v-for='(info,index) in menus'> <!-- 这里我index+1 -->
<h3>{{info.classNum+'班'}} - {{index+1}} - {{'学号:'+info.id}} - {{'名字:'+info.name}}</h3>
</li>
</ul>
</div>
<script src="./vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
classNum: 34,
menus: [
{ id: 1, name: 'Zhang' },
{ id: 2, name: 'Lee' },
{ id: 3, name: 'Wang' },
{ id: 4, name: 'Zhao' }
]
}
})
</script>
- 34班 - 1 - 学号:1 名字:Zhang
- 34班 - 2 - 学号:2 名字:Lee
- 34班 - 3 - 学号:3 名字:Wang
- 34班 - 4 - 学号:4 名字:Zhao
也可以用 of 替代 in 作为分隔符,因为它更接近 JavaScript 迭代器的语法:
<div v-for="item of items"></div>
在 v-for 中使用对象
也可以用 v-for 来遍历一个对象的属性,并提供了两个参数,属性名 和 索引
<div id="app">
<ul>
<li v-for='(value,key,index) of person'>
<h3>{{index}} - {{key}}: {{value}}</h3>
</li>
</ul>
</div>
<script src="./vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
classNum: 34,
person: {
name: 'Max',
age: 23,
height: '182cm'
}
}
})
</script>
- 0 - name: Max
- 1 - age: 23
- 2 - height: 182cm
:key='index'
vue建议在使用 v-for 的时候,通过 :key='index' 或 :key='key' 给每个元素绑定一个属性,这样是为了给每一个元素添加独有的身份,当修改其中某个数据的时候,只更新对应的元素,而不是更新整个 v-for 块
<li v-for='(value,key,index) of person' :key='index'>
<h3>{{index}} - {{key}}: {{value}}</h3>
</li>
不要使用对象或数组之类的非基本类型值作为
v-for的key,请用字符串或数值类型的值
v-model 双向数据绑定
用 v-model 指令在表单元素 <input> <textarea> <select> 上创建双向数据绑定,它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
v-model会忽略所有表单元素的value、checked、selected属性的初始值而总是将 Vue 实例的数据作为数据来源,应该通过 JavaScript 在组件的data选项中声明初始值
v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
- text 和 textarea 元素抛出
value属性,和input事件;- checkbox 和 radio 抛出
checked属性,和change事件;- select 字段将
value作为属性抛出,并将change作为事件。
通过 {{ }} 和 v-modul='' 为两个元素绑定同一个属性,当更改input中的内容时,v-modul 会实时更改所绑定的属性的值,并实时更新到绑定该属性的元素上
# 文本
<p>Message is: {{ message }}</p>
<input v-model="message" placeholder="输入信息">
message:''
# 多行文本
<p>Multiline message is:<br>{{ message }}</p>
<textarea v-model="message" placeholder="输入说明"></textarea>
message:'有什么想说的'
在
<textarea>插值并不会生效,如果有需要可以给message赋值
# 复选框
单个复选框,绑定到布尔值:
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{checked}}</label>
checked: false
//以上代码checked文字会显示为true或false
//-----------------------------------
//如果需要根据状态显示不同的文本,需要在标签内加上判断属性
<input type="checkbox" v-model="checked" true-value="选中了" false-value="没有选中">
<p>{{toggle}}</p>
checked:'没有选中',
这里的
true-value和false-value属性并不会影响输入控件的value属性,因为浏览器在提交表单时并不会包含未被选中的复选框。如果要确保表单中这两个值中的一个能够被提交,(即“yes”或“no”),请换用单选按钮。
多个复选框,绑定到同一个数组:勾选对应的选项 v-model 会把对应元素的value添加到数组中
<div>
<span>Checked names: {{checkedNames}}</span>
<br>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
</div>
checkedNames: []
# 单选按钮
勾选对应的选项 v-model 会把对应元素的value赋值给 v-model 绑定的属性
<div>
<span>Picked: {{picked}}</span>
<br>
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
</div>
picked: ''
# 选择框
下拉选择对应的选项 v-model 会把对应元素的value赋值给 v-model 绑定的属性,如果没有value,则会选择option中间的值
单选时:
<div>
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
selected: ''
如果
v-model表达式的初始值未能匹配任何选项,<select>元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。因此,更推荐像上面这样提供一个值为空的禁用选项。
多选时 (绑定到一个数组):
<div>
<select v-model="selected" multiple style="width: 100px;">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<br>
<span>Selected: {{ selected }}</span>
</div>
selected: []
# 用 v-for 渲染动态选项
<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
selected: 'A',
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
]
# 修饰符
.lazy
在默认情况下,
v-model在每次input输入每个新的字符后都会更新绑定属性的值,可以添加.lazy修饰符,让input失去焦点后再更新:<input v-model.lazy="msg">
.number
如果想自动将用户的输入值转为数值类型,可以给
v-model添加number修饰符:<input v-model.number="age" type="number">因为即使在
type="number"时,HTML 输入元素的值也总会返回字符串。如果这个值无法被parseFloat()解析,则会返回原始的值。
.trim
如果要自动过滤用户输入的首尾空白字符,可以给
v-model添加trim修饰符:<input v-model.trim="msg">
侦听属性 watch
vue通过 watch 提供了一个方法,来响应数据的变化,当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的
把需要监听的属性放到 watch 内,函数接收两个参数,新值和旧值,可以实时侦听数值每次的变化,并调用函数通过条件判断触发相应的事件
watch: {
num: function (newV, oldV) {
console.log(newV,oldV);
}
},
例:
<p>{{num}}</p>
<input v-model="num" type="number">
data: {
num: ''
},
watch: {
num: function (newV, oldV) {
if (newV > 100) {
console.log('超出了');
}
}
},
深度侦听
上面的方法只能侦听基本数据类型,做不到复杂数据类型 对象 和 数组 这种内部值的侦听,对此vue提供了深度监听方法,将需要监听的对象放入watch中,{ }内写入 deep: true 和 handler 函数,函数名必须为 handler 不可更改
<h3>{{person[0].name}}</h3>
<button @click='person[0].name = "Jerry"'>Jerry</button>
watch: {
person: {
deep: true,
handler: function (newV, oldV) {
console.log(newV[0].name);
}
}
},
计算属性 computed
{{ }} 内的表达式非常便利,但是设计它的初衷是用于简单运算的,在模板中放入太多的逻辑会让模板过重且难以维护,例如:
<p>{{ say.split('').reverse().join('') }}</p>
这里不再是简单的声明式逻辑,需要时间理解,当需要在模板中多次引用时,就会让模板变得非常复杂
所以对于任何复杂逻辑,都应当使用计算属性
computed默认只有getter方法
<h3>{{reverseSay}}</h3>
say: 'hello world!'
computed: {
reverseSay: function () {
return this.say.split('').reverse().join('')
}
},
计算属性最大优点:获得属性的值后会立即计算好结果并存入缓存中,需要可立即调用,多次调用不需要函数重新计算,当数据发生变化会重新计算,重新缓存,性能开销小
<h3>{{fullName}}</h3>
<button @click='nameBtn'>更改</button>
data: {
firstName: 'Max',
lastName: 'uan'
},
methods: {
nameBtn: function () {
return this.lastName = 'Max';
}
},
computed: {
fullName: function () {
return this.firstName + this.lastName;
}
},
为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算,然后我们可能有其他的计算属性依赖于 A,如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果不希望有缓存,可用方法来替代。
计算属性的 setter
计算属性默认获取属性(getter),只能通过引入方法来显示结果,不过在需要时也可以对属性进行修改(setter):
触发事件1对val1赋值,Value会跟着被计算属性修改,触发事件2对Value赋值会通过set方法接收新值对val2赋值
但是由于计算属性是在监测到 get 方法内属性变化才开始计算,所以在 set 内被赋值的属性没有出现在 get 中时,对计算属性赋值并不会改变和更新计算属性自身的值,只是通过 set 的 newV 参数传入了函数
<div id="app">
<h3>val1:{{val1}}</h3>
<h3>value:{{value}}</h3>
<h3>val2:{{val2}}</h3>
<button @click='handleClick1'>Val1 = 5</button>
<button @click='handleClick2'>Value = 10</button>
</div>
<script src="./vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
val1: 1,
val2: 2
},
methods: {
handleClick1: function () {
this.val1 = 5;
},
handleClick2: function () {
this.value = 10;
}
},
computed: {
value: {
get: function () {
return this.val1;
},
set: function (newV) {
this.val2 = newV;
}
}
}
})
</script>
计算属性 vs 侦听属性
Vue 提供的侦听属性很方便,当有一些数据需要随着其它数据变动而变动时,很容易滥用 watch,但通常更好的做法是使用计算属性而不是命令式的 watch 回调,例子:
<div>{{ fullName }}</div>
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
上面代码是命令式且重复的,将它与计算属性的版本进行比较:
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
监听属性是更改属性值,所以需要声明fullName,以及分别监听 first 和 last 两个属性的改变
计算属性不再需要声明fullName,而是直接通过计算属性的方法名来引入
过滤器 filters
vue过滤器可用于对数据的修饰处理,过滤器可以用在两个地方:双花括号插值和 v-bind 表达式,过滤器应该被添加在 js 表达式的尾部,由“管道”符号指示:
属性名 | 过滤器名(可传参)
<!-- 在双花括号中 -->
{{ price | myPrice($) }} // $50
<!-- 在 v-bind 中 -->
<div v-bind:id="rawId | formatId"></div>
price: 50
filters:{
myPrice:function(price,a){
return a + price;
}
}
创建全局过滤器
全局过滤器只需创建一次,就可以在所有组件中使用,过滤器名需要用 '' 包裹,否则会报错
Vue.filter('myFilter', (val) => {
return val.split('').reverse().join('');
})