1 初识Vue
1.1 Vue安装
安装Vue的方式有很多:
方法一: 直接CDN引入
<!--开发环境版本,包含了有帮助的命令行警告-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!--生产环境版本,优化了尺寸和速度->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>方法二:下载和引入
开发环境 https://vuejs.org/is/vue.js
生产环境 https://vueis.org/is/vue.min.js方式三: NPM安装
稍后详细说明
1.2 Hello Vue
我们来做第一个Vue程序,体验一下Vue的响应式
|
代码做了什么事情?
我们创建了一个Vue对象: app
创建Vue对象的时候,传入了一些options: {}
- {}中包含了el属性,该属性决定了这个Vue对象挂载到哪个元素上,很明显我们这里是挂载到了id为app的元素上
- {}中包含了data属性: 该属性会存储一些数据
- [x] 这些数据可以是我们直接定义出来的,比如上面这样
- [x] 也可能是来自于网络,从服务器端加载的
浏览器执行代码的流程:
- [x] 执行到HTML中部分显示出对应的HTML
- [x] 执行到let app = new Vue创建Vue实例,并且对原HTML进行解析和修改并且我们的代码是响应式的
1.3 Vue列表显示
现在我们展示一个更加复杂的数据: 数据列表
比如我们现在从服务器请求过来一个列表,希望展示到HTML中, 直接上代码:
<div id="app">
<ul v-for="movie in movies"> // 使用v-for指令
<li>{{movie}}</li>
</ul>
</div>
<script src="./js/vue.js"></script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: { // 定义数据
message: 'Hello, World!',
movies: ['霸王别姬', '肖申克的救赎', '阿甘正传', '星际穿越', '大话西游']
}
})
</script>使用v-for指令可以简化代码,我们不需要在JavaScript代码中拼接DOM了
而且更重要的是,它还是响应式的。
1.4 v-on指令和methods属性
现在我们实现一个小计数器,点击+计数器j+1,点击-计数器-1
<div id="app">
<h2>当前计数: {{counter}}</h2>
<button @click="add">+</button>
<button @click="sub">-</button>
</div>
<script src="./js/vue.js"></script>
<script>
const app = new Vue({
el: '#app', // 用于挂载要管理的元素
data: { // 定义数据
counter: 0
},
methods: {
add() {
this.counter++
},
sub() {
this.counter--
}
}
})
</script>- 新的属性: methods,该属性用于在Vue对象中定义方法
- 新的指令:@click(v-on:click的简写)用于监听某个元素的点击事件,并且制定当发生点击时,执行的方法(通常是methods中定义的方法)
到目前为止我们掌握了这些选项:
el
- 类型: string| HTMLElement
- 作用:决定之后Vue实例会管理哪个DOM
data:
* 类型: Object| Function
* 作用: Vue实例对象对应的数据对象methods:
* 类型:{ [key: string]: Function }
* 作用:定义属于Vue的一些方法,可以在其他地方调用, 也可以在指令中使用
1.4 v-bind动态绑定style
操作元素的 class 列表和内联样式是数据绑定的一个常见需求。因为它们都是属性,所以我们可以用
v-bind
处理它们:只需要通过表达式计算出字符串结果即可。不过,字符串拼接麻烦且易错。因此,在将v-bind
用于class
和style
时,Vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。我们可以传给
v-bind:class
一个对象,以动态地切换 class:<div v-bind:class="{ active: isActive }"></div>
上面的语法表示
active
这个 class 存在与否将取决于数据属性isActive
的 truthiness。你可以在对象中传入更多属性来动态切换多个 class。此外,
v-bind:class
指令也可以与普通的 class 属性共存。当有如下模板:<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>和如下 data:
data: {
isActive: true,
hasError: false
}结果渲染为:
<div class="static active"></div>
当
isActive
或者hasError
变化时,class 列表将相应地更新。例如,如果hasError
的值为true
,class 列表将变为"static active text-danger"
。绑定的数据对象不必内联定义在模板里:
<div v-bind:class="classObject"></div>
data: {
classObject: {
active: true,
'text-danger': false
}
}需要注意,在模板渲染时vue可能会把固定值解析为变量:
<div id="app">
<p :style="{ fontSize: finalSize + 'px', backgroundColor: 'blue' }"> {{message}}</p>
</div>
<script src="./js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'aaaaa',
finalSize: 50
}
})如
px
,默认情况下会被解析为一个变量;如果想确保其被解析为50px,需要在px
前后用单引号括起。1.5 计算属性
1.5.1 使用场景
我们在模板中可以直接通过差值语法显示一些data数据,但是某些情况下,我们可能需要对数据进行一些转化后再显示
- 比如我们有firstName和lastName两个变量,我们需要展示完整名称
- 但是如果有多个地方都需要显示完整名称,我们就需要写多个
此时我们可以将上面代码转换成计算属性,如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h2>{{fullName}}</h2> <!--此处fullName已经作为一个属性值存在-->
</div>
<script src="./js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
firstName: 'Kobe',
lastName: 'Briant'
},//计算属性
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
</script>
<style>
</style>
</body>
</html>另一个案例,将books中书的总价格动态显示出来:
<div id="app">
<h1 v-for="(book, index) in books">{{index+1}}-{{book.name}}</h1>
<h2>总价格:{{totalPrice}}</h2>
</div>
<script src="./js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
books: [
{id: 110, name: '深入理解计算机系统', price: 98},
{id: 110, name: 'Unix网络编程', price: 98},
{id: 110, name: 'Python学习手册', price: 98},
{id: 110, name: 'Vue实战指南', price: 98}
]
},//计算属性
computed: {
totalPrice: function () {
let result = 0
for (let i=0; i < this.books.length; i++) {
result += this.books[i].price
}
return result
}
}
})
</script>1.5.2 set及get方法
计算属性一般是没有set方法的,是只读属性(只有get方法)
data: {
firstName: 'Kobe',
lastName: 'Bryant'
},
computed: {
// 计算属性一般没有set方法,是只读属性
fullName: {
get: function () {
return this.firstName + ' ' + this.lastName
}
}
}亦可简写成:
computed: {
// 在调用计算属性fullName时,实际上调用的就是fullName的get方法
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}在某些情况下需要对计算属性的结果重新赋值,则需要手工实现计算属性的
set
方法:data: {
firstName: 'Kobe',
lastName: 'Bryant'
},
computed: {
// 计算属性一般没有set方法,是只读属性
fullName: {
set: function(newName){ // 通过set方法将计算属性的显示改成James Lebron: app.fullName='James Lebron'
console.log('-------')
const names = newName.split(' ');
this.firstName = names[0]
this.lastName = names[1]
},
get: function () { // 默认显示Kobe Bryant
return this.firstName + ' ' + this.lastName
}
}
}1.5.3 计算属性和methods对比
在下面案例中,我们分别用计算属性和methods方法打印fullName, 并且每调用一次打印一条记录,看看分别使用计算属性和methods方法分别要调用相应函数几次:
<div id="app">
<!--通过定义methods-->
<h2>{{getFullName()}}</h2>
<h2>{{getFullName()}}</h2>
<h2>{{getFullName()}}</h2>
<h2>{{getFullName()}}</h2>
<!--通过计算属性-->
<h2>{{fullName}}</h2>
<h2>{{fullName}}</h2>
<h2>{{fullName}}</h2>
<h2>{{fullName}}</h2>
</div>
<script src="./js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
firstName: 'Kobe',
lastName: 'Bryant'
},
methods: {
getFullName() {
console.log('getFullName')
return this.firstName + ' ' + this.lastName
}
},
computed: {
fullName: function () {
console.log('fullName')
return this.firstName + ' ' + this.lastName
}
}
})得到输出如下:
getFullName
getFullName
getFullName
getFullName
fullName可以看到同样是显示4次fullname,methods方法调用了4次,而计算属性只调用了一次。
- 两种方式的最终结果确实是完全相同的。
- 不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。
- 这就意味着只要
message
还没有发生改变,多次访问reversedMessage
计算属性会立即返回之前的计算结果,而不必再次执行函数。
1.6 事件监听
在前端开发中,我们常常和用户交互。
- 在这个时候,我们就必须监听用户发生的事件,比如点击、拖拽、键盘事件等
- 在Vue中如何监听事件呢?我们使用v-on指令
v-on介绍
- 作用:绑定事件监听器
- 缩写:@
- 预期:Function | Inline Statement | Object
- 参数: event
下面我们就具体来学习v-on的使用
<div id="app">
<h2>点击次数:{{counter}}</h2>
<button v-on:click="counter++">+1</button>
<button v-on:click="counter--">-1</button>
</div>如上,我们可以使用v-on实现了对点击事件的响应
注:v-on有其简写形式,称作语法糖,v-on:click可以简写为***@click***
v-on参数
当通过methods中定义方法,以供**@click**调用的时候,需要注意参数问题:
- 情况一: 如果该方法不需要额外参数,那么方法后的()可以不添加
- 但是注意,如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去
- 情况二:如果需要同时传入某个参数,同时需要event时,可以通过$event传入事件
<div id="app">
<h2>点击次数: {{counter}}</h2>
<button @click="handleAdd">+1</button>
<button @click=handleAddTen(10, $event)>+10</button>
</div>
methods: {
handleAdd(event) {
console.log(event);
this.counter++;
},
handleAddTen(count, event) {
console.log(event);
this.counter += 10;
}
}.stop修饰符的使用
在某些情况下,我们拿到event的目的可能是进行一些事件的处理
Vue提供了修饰符来帮助我们方便的处理一些事件:
- .stop - 调用event.stopPropagation()
- .prevent - 调用event.preventDefault()
- .(keyCode | keyAlias) - 只当时间是从特定键触发时才触发回调
- .native - 监听组件根元素的原生事件
- .once - 只触发一次的回调
例子:
<!-- 1.stop修饰符的使用 -->
<div @click="divclick">
aaaaaa
<button @click.stop="btnClick">按钮</button>
</div>
<!-- 2.prevent修饰符的使用(阻止默认行为) -->
<form action="www.baidu.com">
<input type="submit" value="提交" @click>
</form>
<!-- 3.监听某个键盘的事件 -->
<input type="text" @keyup.enter="keyUp">
<!-- 4.once修饰符的使用(只会触发一次) -->
<button @click.once="doThis"></button>1.7 条件判断
没啥说的直接代码示例:
<div id="app">
<h2 v-if="score>=90">优秀</h2>
<h2 v-else-if="score>=80">良好</h2>
<h2 v-else-if="score>=60">优秀</h2>
<h2 v-else>不及格</h2>
</div>一个小案例
<div id="app">
<span v-if="isUser">
<label>用户账号:</label>
<input type="text" id="username" placeholder="用户账号">
</span>
<span v-else>
<label>邮箱地址: </label>
<input type="text" id="email" placeholder="邮箱地址">
</span>
<button @click="handleToggle">切换类型</button>
</div>如果我们在有输入内容的情况下,切换了类型,我们会发现文字依然显示之前输入的内容
但是按道理, 我们应该切换到另外一个input元素中了
在另一个input元素中,我们并没有输入内容
为什么会出现这个问题呢
(如图,点击切换类型后输入框中的内容一直存在)
问题解答
- 这是因为Vue在进行DOM渲染时,出于性能考虑,会尽可能的复用已经存在的元素, 而不是重新创建新的元素
- 在上面的案例中,Vue内部会发现原来的input元素不再使用,直接作为else中的input来使用了
解决方案
- 如果我们不希望Vue出现类似重复利用的问题,可以给对应的input添加key
- 并且我们需要保证key是不同的
(如图,在添加不同key后再次点击切换类型,此时原本input元素中的内容就不会保留了)
v-if 和 v-show在控制元素显示时的区别:
v-if: 当条件为false时,包含v-if指令的元素,根本不会存在于dom中
v-show: 当条件为false时,v-show并不删除元素,只是给我们的元素增加一个行内样式: display: none
1.8 v-for遍历
v-for遍历数组
当我们有一组数据需要进行渲染时,我们就可以使用v-for来完成
- v-for的语法类似于JavaScript中的for循环
- 格式如下: item in items的形式
我们来看一个简单的案例:
- 如果在遍历的过程中不需要使用索引值
- v-for=”movie in movies”
- 依次从movies中取出movie,并在元素内容中,我们可以使用Mustache语法,来使用movie
- 如果在遍历的过程中,我们需要拿到元素在数组中的索引值呢
- 语法格式: v-for=(item, index) in items
- 其中的index就代表了取出的item在原数组的索引值
专题:哪些数组的方法是响应式的
push方法:在数组后面增加元素
this.letters.push()
pop方法:内删除数组中最后一个元素
this.letters.pop()
shift方法:删除数组中第一个元素
this.letters.shift()
unshift方法:在数组最前面添加元素
splice方法:删除元素/插入元素/替换元素
删除元素:第二个参数传入要删除几个元素(如果没有传则删除后面所有元素)
this.letters.splice(1, 3) # 删除第一个元素后三个元素
替换元素:从第几个元素开始,替换几个元素,分别是什么
this.letters.splice(1, 3, ‘m’, ‘n’, ‘o’)
插入元素:第二个参数,传入0, 并且后面跟上要插入的元素
this.letters.splice(1, 0, ‘x’, ‘y’, ‘z’) # 在第一个元素后面插入x, y, z
sort方法
this.letters.sort()
reverse方法
this.letters.reverse()
1.9 补充:高阶函数
三种高阶函数:
- filter: filter中的回调函数有一个要求,必须返回一个boolean值,
- 当返回true时, 函数内部自动将这次回调的n加入到新的数组中
- 当返回false时,函数内部会过滤掉这次的n
const nums = [10, 20, 111, 222, 333, 40, 50]
let newNums = nums.filter(function(n) {
return n < 100
})
console.log(newNums)
newNums2 = nums.filter(n => {
return n < 100
})
console.log(newNums2)- map: 对原数组中所有元素执行操作组成一个新的数组
let newNums = nums.map(function(n) {
return n * 2
})- reduce: reduce会对数组中所有的内容进程汇总,返回一个值
let total = nums.reduce(function (preValue, n) { // 前值,当前值
return preValue + n
}, 0) // 第二个参数是初始值1.10 v-model
表单绑定v-model
- 表单控件在实际开发中是非常常见的,特别是对于用户信息的提交,需要大量的表单
- Vue中使用v-model指令来实现表单元素和数据的双向绑定
- 案例解析
- 当我们在输入框输入内容时,因为input中v-model绑定了message,所以会实时将输入的内容传递给message,message发生改变
- 当message发生改变时,因为上面我们使用Mustache语法,将message的值插入到DOM中,所以DOM会发生相应的改变
- 所以v-model实现了数据的双向绑定
<div id="app">
<input type="text" v-model="message">
<h2>{{ message }}</h2>
</div>
<script src="./js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: "Hello World!"
}v-model原理
v-model其实是一个语法糖,它背后本质上包含两个操作:
- v-bind绑定一个value属性
- v-on指令给当前元素绑定input事件
也可以使用v-bind和v-on实现v-model的功能:
<input type="text" v-model="message">
等同于
<input type="text" v-bind:value="message" v-on:input="message = $event.target.value">v-model用于radio
设想这样一个场景,在表单提交的过程中需要选择性别,要么男要么女
首先要使两个选项互斥,需要给两个选项指定相同的name:
<div id="app">
<label for="male">
<input type="radio" id="male" name="sex" value="male">男
</label>
<label for="female">
<input type="radio" id="female" name="sex" value="female">女
</label>
<h2>选择的性别是:{{ sex }}</h2>
</div>当两个radio指定了相同的name=“sex”时,浏览器认为这两个radio是互斥的,这样在页面上这两个选项只能被选中一个
如果使用v-model处理互斥选项,则不需要指定相同的name=”sex”, 而只需要让这两个radio绑定相同的data即可:
<div id="app">
<label for="male">
<input type="radio" id="male" value="male" v-model="sex">男
</label>
<label for="female">
<input type="radio" id="female" value="female" v-model="sex">女
</label>
<h2>选择的性别是:{{ sex }}</h2>
</div>
<script src="./js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
sex: 'male'
}如上,只需要将两个radio都指定v-model=”sex”,那么在页面上他们就是互斥的;同时还可以在data中指定初始值sex: ‘male’, 这样在页面上默认的性别值就是male, 体现了Vue数据驱动的特点。
v-model用于checkbox
复选框分为两种情况:单选框和多选框
单个勾选框:
- v-model即为bool值
- 吃屎input的value并不影响v-model的值
多个复选框
- 当是多个复选框时,因为可以选中多个,所以对应的data中的属性时一个数组
- 当选中某一个时。就会将input的value添加到数组中
<div id="app">
<!-- 单选框 -->
<label for="license">
<input type="checkbox" id="license" v-model="isAgree">同意协议
</label>
<h2>您选择的是:{{ isAgree }}</h2>
<button :disabled="!isAgree">下一步</button>
<hr>
<!--多选框-->
<input type="checkbox" value="唱" v-model="hobbies">唱
<input type="checkbox" value="跳" v-model="hobbies">跳
<input type="checkbox" value="rap" v-model="hobbies">rap
<input type="checkbox" value="篮球" v-model="hobbies">篮球
<h2>您的爱好是: {{ hobbies }}</h2>
</div>
<script src="./js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
isAgree: false,
hobbies: []
}
})
</script>v-model用于select
和checkbox一样,select也分为单选和多选的情况
- 单选:只能选中一个值
- v-model绑定的是一个值
- 当我们选中option中的一个时,会将它对应的value赋值到mySelect中
- 多选:可以选中多个值
- v-model绑定的是一个数组
- 当选中多个值时,就会将选中的option对应的value添加到数组中
<div>
<!-- select 选中一个-->
<select name="fruits" v-model="fruit">
<option value="apple">苹果</option>
<option value="banana">香蕉</option>
<option value="orange">橘子</option>
<option value="peach">桃子</option>
</select>
<h2>您选择的水果是:{{ fruit }}</h2>
<!-- select选中多个 -->
<select name="fruits" v-model="fruits" multiple>
<option value="apple">苹果</option>
<option value="banana">香蕉</option>
<option value="orange">橘子</option>
<option value="peach">桃子</option>
</select>
<h2>您选择的水果分别是:{{ fruits }}</h2>
</div>
<script src="./js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
fruit: '',
fruits: []
}
})
</script>也可以用值绑定的方式,直接代码:
<div>
<label v-for="item in balls" :for="item">
<input type="checkbox" :value="item" :id="item" v-model="selectBalls" >{{ item }}
</label>
<h2>您选择的球有: {{ selectBalls }}</h2>
</div>
<script src="./js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
balls: ['篮球', '足球', '羽毛球', '弹珠球'],
selectBalls: []
}
})
</script>修饰符
lazy修饰符:
- 默认情况下, v-model默认是在input事件中同步输入框的数据的。
- 也就是说,一旦有数据发生改变对应的data 的数据就会自动发生改变。
- lazy修饰符可以让数据在失去焦点或者回车时才会更新:
number修饰符:
默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理。
但是如果我们希望处理的是数字类型,那么最好直接将内容当做数字处理。
number修饰符可以让在输入框中输入的内容自动转成数字类型
trim修饰符:
如果输入的内容首尾有很多空格,通常我们希望将其去除
trim修饰符可以过滤内容左右两边的空格
欢迎关注我的其它发布渠道