一. 环境准备
1 准备Node环境
由于大部分Vue项目都是依赖于Node环境. 在开始之前, 我们需要先准备好Node环境
访问Node中文官网下载最新版的Node.js
找到下载的node-v12.16.1-x64.msi, 双击安装
2 配置npm镜像
npm默认的仓库地址是在国外网站,速度较慢,建议大家设置到淘宝镜像。但是切换镜像是比较麻烦的。推荐一款切换镜像的工具:nrm
我们首先安装nrm,这里-g
代表全局安装
npm install nrm -g
通过nrm ls命令查看npm的仓库列表,带*的就是当前选中的镜像仓库
3 安装Vue
1) 初始化
使用如下指令初始化
npm init -y
发现在目录下会多一个文件package.json, 这个文件用来管理该项目使用了哪些包
2) 安装vue
执行如下命令安装vue
npm install vue --save
以上命令可以简写为
npm i vue
在项目目录会产生一个文件夹node_modules和一个文件package-lock.json
扩展
vue的各种版本
vue.js是完整版, (在初学阶段使用)
- common: 使用CommonJS规范导入导出
module.exports
,这种文件不能在浏览器中使用 - esm(ES Module): 使用ES的模块规范导入导出
export default
- runtime: 运行时版本, 相对于编译版本, 体积更小, 效率更高
二. 使用Vue
vue使用的3步曲
- 引入vue.js
- 编写页面(视图)
- 编写vue实例
1 引入vue.js
在html的头部, 通过<script src>
引入vue.js
这里我用到了VSCode插件: Path Intellisense 快速补全路径
示例
<!-- 1. 引入vue.js -->
<script src="../node_modules/vue/dist/vue.js"></script>
2 编写页面(视图)
在boby中, 编写一个div
元素, id为app, 所有视图部分将在这部分渲染
示例
<!-- 2. 编写页面 -->
<div id="app"></div>
3 编写vue实例
在body的最末尾, 使用<script>
, 编写vue实例
示例
<!-- 3. 编写vue实例 -->
<script>
const vm = new Vue({
el: '#app', // 对应操作的元素, 必填参数
data: {}, // 数据部分
methods: {} // 方法部分
})
</script>
将数据渲染到页面中
1) 定义数据
在data中定义数据
示例
<!-- 3. 编写vue实例 -->
<script>
const vm = new Vue({
el: '#app', // 对应操作区的元素, 必填参数
data: {
msg: 'hello world'
}, // 数据部分
methods: {} // 方法部分
})
</script>
使用键值对方式定义数据. 其中
示例
<div id="app">
{{ msg }}
</div>
MVVM由 Model(数据模型) View(视图) 和 VM(ViewModel) 组成
核心思想
实现 数据 与 视图 的 双向绑定
各自的作用
- Model(数据模型): 操作数据
- View(视图): 显示数据
- VM: 模型与视图间的双向操作
双向绑定:
Vue 应用的核心就是 Vue 实例 , 一个基本的 Vue 实例包括如下图所示:
new Vue({
el: '#app',
data: {},
methods: {}
})
- el: 表示要操作的页面元素
- data: 数据, 可以理解为面向对象中类的”属性“
- methods: 方法, 可以理解为面向对象中类的”方法“
属性
当 Vue 实例创建时, 会获取 data 中的数据, 并渲染到视图中, 并监视 data 中数据的变化, 当 data 中的数据改变时, 重新渲染视图
方法
方法就是: 响应视图中的事件, 并修改 data 里的数据
重要结论
在 src 目录下创建03_加法器.html
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>03_加法器</title>
<!-- 1. 引入vue.js -->
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<!-- 2. 编写div元素 -->
<div id="app"></div>
<!-- 3. 编写vue实例 -->
<script>
const vm = new Vue({
el: '#app'
})
</script>
</body>
</html>
2) 编写页面
分析
页面由两个 input 框和一个按钮, 再加一个 input 框组成
示例
<div id="app">
<input type="text" />+<input type="text" />
<button>=</button>
<input type="text" />
</div>
2 绑定属性
使用 v-model 绑定属性
html 部分
<div id="app">
<input v-model="first" type="text">+<input v-model="second" type="text">
<button>=</button>
<input v-model="result" type="text">
</div>
js 部分
const vm = new Vue({
el: '#app', // 元素
data: {
first: 0,
second: 0,
result: 0
}, // 属性
methods: {} // 方法
})
3 绑定方法
使用 v-on 绑定click方法
html 部分
<button v-on:click="add">=</button>
js 部分
methods: {
add() {
this.result = parseInt(this.first) + parseInt(this.second)
}
} // 方法
五. 模板语法
什么是模板
:::info 由Vue解析的HTML字符串 :::
什么是模板语法
:::info 在模板字符串中, 具有特殊意义的语法, 通常就是一些vue指令 :::
模板语法主要用于视图的编写,以v-
指令. 常见的有
- 属性绑定: v-bind, 简写为
:
- 方法绑定: v-on, 简写为
@
- 双向绑定: v-model
- 条件渲染: v-if
- 列表渲染: v-for
1 属性绑定和双向绑定
在src目录下, 创建04_属性绑定.html
, 完成vue的3步曲
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>04_属性绑定</title>
<!-- 1. 引入vue.js -->
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<!-- 2. 编写div元素 -->
<div id="app"></div>
<!-- 3. 编写vue实例 -->
<script>
const vm = new Vue({
el: '#app'
})
</script>
</body>
</html>
属性绑定
:::info 将 非表单标签 的一个属性和data中的一个变量绑定 :::
html部分
<!-- 完整的写法 -->
<a v-bind:href="url">百度</a>
<!-- 简写(推荐) -->
<a :href="xzd">新中地</a>
vue官方更推荐简写的方式
js部分
const vm = new Vue({
el: '#app',
data: {
url: 'http://baidu.com'
}
})
- 将a标签
href
属性和data中的url变量绑定 - 相当于
<a href="http://baidu.com"></a>
特别说明
在指令后面的引号中, 可以使用类似于{{}}
中一样的语法.
- 可以使用
js表达式
- 直接访问
vm
实例上的属性和方法
上面的代码, 被Vue解析成DOM如下:<!-- 在指令后面的""中, 可以使用跟{{}}中一样的代码 --> <div :data-test="msg + 'world'"></div>
<div data-test="helloworld"></div>
双向绑定
双向绑定的原理
- 通过绑定
input
框架的value属性和data中的一个变量, 实现了数据->视图的单向绑定 - 监听
input
框架的input事件, 当事件触发时, 更新data中的变量
将 表单标签 的value值和data中的变量双向绑定
html部分
<input type="text" v-model="uName" />
js部分
const vm = new Vue({
el: '#app',
data: {
uName: 'xiaoming'
}
})
- 将input标签的value属性和data中的uName变量绑定
- 相当于
<input type="text" value="xiaoming" />
小结
对于input
元素. v-model
默认
- 绑定
value
属性 - 监听
input
事件
:::tips
💡 注意
不同的表单元素, 绑定的属性和监听的事件不同
2 事件处理
1) 事件监听
语法
v-on:input<br /> 简写<br /> @input
几种情况
**不写括号 (70%)**<br /> 应用<br /> 不需要传递自定义参数<br /> 事件对象<br /> 在methods定义中通过形参接收<br /> **写括号 (30%)**<br /> 应用<br /> 1 需要传递自定义参数, 不传事件对象 (20%)<br /> 调用时<br /> 函数名(实参列表)<br /> 声明时<br /> 函数名(形参列表)<br /> 2 需要传递自定义参数, 也传递事件对象 (10%)<br /> **调用时**<br />** 函数名(实参列表, $event)**<br />** 声明时**<br />** 函数名(形参列表, e)**
2) 事件修饰符
常见的事件修饰符
.stop
阻止冒泡
.prevent
阻止默认行为
.once
该事件只会触发一次
使用
多个修饰符可以串联使用
3)按键修饰符
概念
Vue 允许为 v-on 在监听键盘事件时添加按键修饰符
常见的按键修饰符
v-on:keyup.keyName (推荐)
eg: @keyup.enter=”fn”
v-on:keyup.keyCode
3 样式渲染
1) 绑定class属性(80%)
A 对象语法
应用
定义
1 先编写对应的css样式
.add1{ color: red }
.add2{ font-size: 40px }
2 然后在data中定义对应属性
data:{ obj:{add1: ture, add2: ture} }
绑定
对象的写法 B 数组语法 (推荐)
应用
定义
1 先编写对应的css样式
.add1{ color: red }
.add2{ font-size: 40px }
2 然后在data中定义对应属性
data:{ arr: [ ‘add1’ , ‘add2’ ] }
绑定
数组的写法 </span
2) 绑定style属性(20%)
A 对象语法
应用
定义
在data中定义对应属性
data:{ obj: { color:’red’, fontSize: ‘40px’ } }
绑定
对象的语法
B 数组语法
可忽略 (跟前者类比)
4 条件渲染
条件渲染
当条件满足时, 渲染到页面
主要指令: v-if
和v-show
1) 完成vue的3步曲
在src目录下, 创建05_条件渲染.html
, 编写vue的基础模板
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>05_条件渲染</title>
<!-- 1. 引入vue.js -->
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<!-- 2. 编写div元素 -->
<div id="app"></div>
<!-- 3. 编写vue实例 -->
<script>
const vm = new Vue({
el: '#app'
})
</script>
</body>
</html>
2) 编写页面与逻辑
示例
html部分
<!-- 2. 编写div元素 -->
<div id="app">
<div v-if="flag">这是用v-if渲染的元素</div>
<div v-show="flag">这是用v-show渲染的元素</div>
</div>
js部分
<script>
const vm = new Vue({
el: '#app',
data: {
flag: true
}
})
</script>
- 当flag为true时, 两个元素都可以显示
- 当flag为false时, 两个元素都不显示, 区别是
- v-if: 不会创建元素
- v-show: 创建元素, 但是display=none
3) 表达式
除了使用变量外, 还可以使用表达式
比如
<div v-if="flag == true">这是用v-if渲染的元素</div>
案例
通过按钮控制元素的显示/隐藏
示例
html部分
<div id="app">
<button @click="flag = !flag">切换</button>
<div v-if="flag">这是用v-if渲染的元素</div>
<div v-show="flag">这是用v-show渲染的元素</div>
</div>
- 绑定按钮的点击事件
- 当flag==true时点击, flag先取反, 再保存, 此时flag为false
- 当flag==false时点击, flag先取反, 再保存, 此时flag为true
5 列表渲染
列表渲染也称”循环渲染”, 通过v-for
遍历数组或者对象
1) 遍历数组
如果只希望得到每个数组元素的值, 不需要得到下标
遍历数组设置key值建议使用book.id (数据本身主键id) 不建议使用index索引下标
语法
v-for="item in items"
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>06_列表渲染</title>
<!-- 1. 引入vue.js -->
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<!-- 2. 编写div元素 -->
<div id="app">
<ul>
<li v-for="item in items">{{ item }}</li>
</ul>
</div>
<!-- 3. 编写vue实例 -->
<script>
const vm = new Vue({
el: '#app',
data: {
items: ['test1', 'test2', 'test3']
}
})
</script>
</body>
</html>
如果只希望得到每个数组元素的值和下标
语法
v-for="(item, index) in items"
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>06_列表渲染</title>
<!-- 1. 引入vue.js -->
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<!-- 2. 编写div元素 -->
<div id="app">
<ul>
<li v-for="(item, index) in items">{{ index }}--{{ item }}</li>
</ul>
</div>
<!-- 3. 编写vue实例 -->
<script>
const vm = new Vue({
el: '#app',
data: {
items: ['test1', 'test2', 'test3']
}
})
</script>
</body>
</html>
2) 遍历对象
- 只取值:
v-for="value in obj"
- 取键和值:
v-for="(value, key) in obj"
- 取键和值和索引:
v-for="(value, key, index) in obj"
遍历对象设置key值建议使用对象的属性值 (如 item) , 因为对象一般属性不会有相同
3) key值使用
1 key属性是vue里面的属性, 不会真实加载到dom中
2 key值一定要是唯一值
3 尽量避免使用数组的下标去绑定key值,一旦数组结构发生变化, 会导致对应key值发生变化
比如在数组前面新增元素
4 如果没有绑定key值, 则默认按照数组索引去设置key值
注意不要忘记设置key 给每个元素唯一标识 !!!!!!!
六. 计算属性与侦听器
1 计算属性
1) 什么是计算属性
:::info 计算属性就是基于现有属性计算后的属性 :::
2) 计算属性的作用
3) 案例
:::warning
需求
实现如下效果
:::
使用表达式实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<!-- 需求: 实现字符串的反转
eg. abc 转换成 cba
-->
<div id="app">
请输入一个字符串: <input type="text" v-model="msg" /> <br />
<!-- 反转字符串的思路
1. 取出字符串中的每个字符 msg.split('') 形成一个数组
2. 反转数据. msg.split('').reverse() 形成一个反转数组
3. 将反转数组拼接. msg.split('').reverse().join('')
-->
<!-- 不推荐!! 在模板中书写复杂的表达式 -->
<h3>反转后的字符串: {{msg.split('').reverse().join('')}}</h3>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
msg: '',
},
})
</script>
</body>
</html>
使用方法实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<!-- 需求: 实现字符串的反转
eg. abc 转换成 cba
-->
<div id="app">
请输入一个字符串: <input type="text" v-model="msg" /> <br />
<!-- 反转字符串的思路
1. 取出字符串中的每个字符 msg.split('') 形成一个数组
2. 反转数据. msg.split('').reverse() 形成一个反转数组
3. 将反转数组拼接. msg.split('').reverse().join('')
-->
<!-- 不推荐使用方法
原因: 没有缓存, 每次调用方法, 代码会执行一次
-->
<h3>反转后的字符串: {{reverseMsg()}}</h3>
<h3>反转后的字符串: {{reverseMsg()}}</h3>
<h3>反转后的字符串: {{reverseMsg()}}</h3>
<h3>反转后的字符串: {{reverseMsg()}}</h3>
<h3>反转后的字符串: {{reverseMsg()}}</h3>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
msg: '',
},
methods: {
reverseMsg() {
console.log('反转函数被执行了...')
// 返回 反转后的字符串
return this.msg.split('').reverse().join('')
},
},
})
</script>
</body>
</html>
使用计算属性实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<!-- 需求: 实现字符串的反转
eg. abc 转换成 cba
-->
<div id="app">
请输入一个字符串: <input type="text" v-model="msg" /> <br />
<!-- 反转字符串的思路
1. 取出字符串中的每个字符 msg.split('') 形成一个数组
2. 反转数据. msg.split('').reverse() 形成一个反转数组
3. 将反转数组拼接. msg.split('').reverse().join('')
-->
<!-- 推荐使用 计算属性
1. 有缓存的. 当计算属性生成一次后, 挂载到vm实例.
后继的访问, 直接使用vm实例上的属性
2. 方便调试
-->
<h3>反转后的字符串: {{reverseMsg}}</h3>
<h3>反转后的字符串: {{reverseMsg}}</h3>
<h3>反转后的字符串: {{reverseMsg}}</h3>
<h3>反转后的字符串: {{reverseMsg}}</h3>
<h3>反转后的字符串: {{reverseMsg}}</h3>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
msg: '',
},
computed: {
// 编写一个函数, 这个函数会被做为该计算属性的getter
reverseMsg() {
console.log('计算属性被执行了...')
// 该函数的返回值, 做为访问计算属性的结果
return this.msg.split('').reverse().join('')
},
},
})
</script>
</body>
</html>
4) 特点
:::info
- 有缓存
- 调试方便 :::
2 侦听器
1) 什么是侦听器
:::info 可以通过watch配置项, 监听data中属性的改变 :::
2) 语法
watch: {
// 监听data中的firstName属性
firstName() {
// 执行一系列的操作
},
},
3) 特点
在watch对应的回调函数中, 可以获取到新值
和 旧值
示例
const vm = new Vue({
el: '#app',
data: {
firstName: '',
lastName: '',
},
// 使用watch这个配置项
watch: {
// 在watch对应的回调函数中, 可以得到新值和旧值
// 对于简单数据类型, 可以获取新旧值
// 对于引用数据类型, 不能获取旧值
firstName(newValue, oldValue) {
// 一对多: 监听某一个属性的改变, 做一系列的操作
console.log('firstName改变了...')
console.log('新的值:', newValue)
console.log('旧的值:', oldValue)
},
},
})
3 区别
- 是否会在vm实例中挂载新属性?
- computed会
- watch不会
- 对应关系
- computed是
多对一
, 可以同时监听多个值改变, 最终计算得到一个新的属性 - watch是
一对多
, 主要监听一个属性的变化, 执行多种逻辑
- computed是
- 能否获取新旧值?
1) 什么是过滤器
:::info 过滤器是一个函数, 主要完成对数据的格式化 :::
2) 语法
{{ 表达式 | 过滤器1 | 过滤器2 ...}}
将表达式的结果作为过滤器1参数, 再将过滤器1的结果作为过滤器2的参数, 依次类推
3) 分类
- 全局过滤器
- 局部过滤器
4) 示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>过滤器</title>
<script src="../node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">金额: {{price | formatPrice}}</div>
<script>
const vm = new Vue({
el: '#app',
data: {
price: 85,
},
filters: {
formatPrice(value) {
console.log(value)
return '¥' + value.toFixed(2) + '元'
},
},
})
</script>
</body>
</html>