Vue2+Vue3 1~45集学习笔记
一、Vue初介绍
1、Vue是什么
(1)概念
Vue是一个用于构建用户界面的渐进式 框架
1、 构建用户界面:基于数据动态渲染页面
2、渐进式:循序渐进的学习
3、框架:一整套完整的项目解决方案,提升开发效率
2、创建一个Vue实例
(1)核心步骤
- 准备容器
- 引包(官网)开发版本包/生产版本包
- 创建Vue实例new Vue()
- 指定配置项
- el指定挂载点(挂载点是 Vue 实例与 DOM(文档对象模型)建立连接的关键位置)
- data提供数据
3、插值表达式
(1)语法
{{表达式}}
(2)作用
利用表达式进行插值,渲染到页面中
表达式:可以被求值的代码,js引擎会将其计算出一个结果
(3)注意点
- 使用数据必须在data中存在
- 支持的是表达式而非语句(if、for不能用)
- 不能在标签属性中使用插值表达式
4、Vue响应式特性
响应式:数据变化,视图自动更新
data中的数据会被添加到实例上(app)
访问数据:实例.属性名
修改数据:实例.属性名=值
二、初识指令
1、Vue指令
Vue会根据不同的指令,针对标签实现不同的功能
指令:带有v-前缀的 特殊标签属性
vue 中的指令按照不同的用途可以分为如下 6 大类:
- 内容渲染指令(v-html、v-text)
- 条件渲染指令(v-show、v-if、v-else、v-else-if)
- 事件绑定指令(v-on)
- 属性绑定指令 (v-bind)
- 双向绑定指令(v-model)
- 列表渲染指令(v-for)
2、内容渲染指令
(1)v-html
- 作用
设置元素的innerHTML,能够将html标签的样式显示出来 - 语法
v-html='表达式'
(2)v-text
- 作用
设置元素的innerText,不能够显示html标签的样式 - 语法
v-text='表达式'
3、条件渲染指令
(1)v-show
- 作用
控制元素显示隐藏 - 语法
v-show='表达式'
表达式true显示,false隐藏 - 原理
切换display的值控制显隐性 - 场景
频繁切换显隐性的场景
(2)v-if
- 作用
控制元素显示隐藏(条件渲染) - 语法
v-if='表达式'
表达式true显示,false隐藏 - 原理
创建或者移除元素节点 - 场景
要么显示要么隐藏
<div id="app">
<div class="box" v-show='flag'>我是v-show控制的盒子</div>
<div class="box" v-if='flag'>我是v-if控制的盒子</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
flag: false
}
})
</script>
(3)v-else和v-else-if
- 作用
辅助v-if进行判断渲染 - 语法
v-else='表达式'
v-else-if='表达式'
- 注意
需要紧接着v-if使用
<div id="app">
<p v-if='gender===1'>性别:♂ 男</p>
<p v-else>性别:♀ 女</p>
<hr>
<p v-if='score>=90'>成绩评定A:奖励电脑一台</p>
<p v-else-if='score>=70'>成绩评定B:奖励周末郊游</p>
<p v-else-if='score>=60'>成绩评定C:奖励零食礼包</p>
<p v-else>成绩评定D:惩罚一周不能玩手机</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
gender: 2,
score: 95
}
})
</script>
4、事件绑定指令
v-on
- 作用
为DOM元素注册事件 - 语法
v-on='内联语句'
<div id="app">
<button @click="changeShow">切换显示隐藏</button>
<h1 v-show="isShow">黑马程序员</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
isShow: true
}
methods:{
changeShow(){
this.isShow=!this.isShow
}
}
})
</script>
v-on='处理函数'
- 事件处理函数应写到一个跟data同级的配置项(methods)中
- methods中的函数内部的this都指向Vue实例(app)
<div id="app">
<button @click="changeShow">切换显示隐藏</button>
<h1 v-show="isShow">黑马程序员</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
isShow: true
}
methods:{
changeShow(){
this.isShow=!this.isShow
}
}
})
</script>
v-on='处理函数(实参)'
- 如果不传递任何参数,则方法无需添加小括号,methods方法中可以直接使用
e
当作事件对象 - 如果传递了参数,则实参
$event
表示事件对象,固定用法
- 如果不传递任何参数,则方法无需添加小括号,methods方法中可以直接使用
<style>
.box {
border: 3px solid #000000;
border-radius: 10px;
padding: 20px;
margin: 20px;
width: 200px;
}
h3 {
margin: 10px 0 20px 0;
}
p {
margin: 20px;
}
</style>
<div id="app">
<div class="box">
<h3>小黑自动售货机</h3>
<button @click='fn(5)'>可乐5元</button>
<button @click='fn(10)'>咖啡10元</button>
<button @click='fn(8)'>牛奶8元</button>
</div>
<p>银行卡余额:{{ money }}元</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
money: 100
},
methods:{
fn(price){
this.money-=price
}
}
})
</script>
- 简写
v-on
可简写为@
5、属性绑定指令
v-bind
- 作用
动态设置html标签的属性,如:src、url、title - 语法
v-bind:'属性名'='表达式'
- 简写
v-bind:
可以简写成:
<div id="app">
<img v-bind:src="imgUrl" v-bind:title="msg" alt="">
<img :src="imgUrl" :title="msg" alt="">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
imgUrl: './imgs/10-02.png',
msg: 'hello 波仔'
}
})
</script>
6、波仔的学习之旅
需求:默认展示数组中的第一张图片,点击上一页下一页来回切换数组中的图片
<div id="app">
<button v-show='index>0' @click='index--'>上一页</button>
<div>
<img :src="list[index]" alt="">
</div>
<button v-show='index<list.length-1' @click='index++'>下一页</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
index:0,
list: [
'./imgs/11-00.gif',
'./imgs/11-01.gif',
'./imgs/11-02.gif',
'./imgs/11-03.gif',
'./imgs/11-04.png',
'./imgs/11-05.png',
]
}
})
</script>
7、列表渲染指令
v-for
- 作用:用来辅助开发者基于一个数组来循环渲染一个列表结构
- 语法
v-for指令需要使用(item,index) in arr
形式的特殊语法,其中- item是数组中的每一项
- index是每一项的索引,不需要可以省略
- arr是被遍历的数组
<div v-for='(item,index) in arr'>{{item}}</div>
- v-for的key属性
- 语法:
key属性='唯一标识'
- 作用:
- 给列表项添加的唯一标识,便于Vue进行列表项的正确排序复用,以小黑的书架为例,直接删除第一个li
- 如果不使用key为列表项添加唯一标识,v-for的默认行为会尝试原地修改元素(就地复用),以小黑的书架为例,保留前三个li,去掉最后一个li,替换其中的文字
- 注意点:
- key的值只能是字符串或者数字类型
- key的值必须唯一
- 推荐使用id作为key的值
8、小黑的书架
<div id="app">
<h3>小黑的书架</h3>
<ul>
<li v-for='(item,index) in booksList' :key='item.id'>
<span>{{item.name}}</span>
<span>{{item.author}}</span>
<button @click='del(item.id)'></button>
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
booksList: [
{ id: 1, name: '《红楼梦》', author: '曹雪芹' },
{ id: 2, name: '《西游记》', author: '吴承恩' },
{ id: 3, name: '《水浒传》', author: '施耐庵' },
{ id: 4, name: '《三国演义》', author: '罗贯中' }
]
},
methods:{
del(id){
this.booksList = this.booksList.filter((item)=>{item.id!==id})
//filter方法不会改变原数组而是会把结果存储到一个新数组中,因此我们要将处理过的数组结果重新返回this.booksList
}
}
})
</script>
9、双向绑定指令
v-model
- 作用:
是给表单元素使用的,双向数据绑定,可以快速获取或设置表单元素
数据变化–>视图自动更新
视图变化–>数据自动更新 - 语法
v-model='变量'
<div id="app">
账户:<input type="text" v-model="username"> <br><br>
密码:<input type="password" v-model="password"> <br><br>
<button @click="login">登录</button>
<button @click="reset">重置</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
username: '',
password: ''
},
methods:{
login(){
console.log(this.username,this.password)
},
reset(){
this.username=""
this.password=""
}
}
})
</script>
10、综合案例——小黑记事本
三、指令的修饰符
通过.
指明一些指令后缀,不同后缀封装了不同的处理操作,可以简化代码
- 按键修饰符
@keyup.enter
键盘回车监听
//不加.enter,执行keyup.enter的方法
<input @keyup="fn">
methods:{
fn(e){
// e可以获取到执行操作的对象,这个对象包括很多属性
if(e.key==='Enter'){
console.log('键盘回车的时候触发')
}
}
}
- v-model修饰符
v-model.trim
去除首尾空格
v-model.number
转数字 - 事件修饰符
@事件名.stop
阻止冒泡
@事件名.prevent
阻止默认行为
四、v-bind操作class
1、语法
:class='对象/数据'
- 对象:键就是类名,值是布尔值,true表示有这个类,false表示没有这个类
<div class='box' :class='{类名1:布尔值,类名2:布尔值}'></div>
适用场景:一个类名,来回切换
- 数组:数组中的所有类,都会添加到盒子上,本质是一个class列表
<div class='box' :class='[类名1,类名2,类名3]'></div>
适用场景:批量添加或删除类
2、京东秒杀-tab栏切换导航高亮
1.需求:
当我们点击哪个tab页签时,哪个tab页签就高亮
2.准备代码:
<style>
* {
margin: 0;
padding: 0;
}
ul {
display: flex;
border-bottom: 2px solid #e01222;
padding: 0 10px;
}
li {
width: 100px;
height: 50px;
line-height: 50px;
list-style: none;
text-align: center;
}
li a {
display: block;
text-decoration: none;
font-weight: bold;
color: #333333;
}
li a.active {
background-color: #e01222;
color: #fff;
}
</style>
<div id="app">
<ul>
<li v-for="(item,index) in list" :key="item.id" @click='index = activeIndex'>
<a :class="{active:index === activeIndex}" href="#">{{item.name}}</a>
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
activeIndex:0,
list: [
{ id: 1, name: '京东秒杀' },
{ id: 2, name: '每日特价' },
{ id: 3, name: '品类秒杀' }
]
}
})
</script>
五、v-bind操作style
1、语法
:style='样式对象'
<div class='box' :style='{css属性名1:css属性值,css属性名2:css属性值}'></div>
属性值要符合css语法==>用引号把属性值包起来
带有-
的属性名,使用小驼峰命名法或用引号引起来
六、v-model应用于其他表单元素
1、常见的表单元素
- input:text输入框 ===> value
- textarea文本域 ===> value
- input:checkbox复选框 ===> checked
- input:radio单选框(加上相同的name属性使两个选项互斥) ===> checked
- select下拉菜单 ===> value
<style>
textarea {
display: block;
width: 240px;
height: 100px;
margin: 10px 0;
}
</style>
<div id="app">
<h3>小黑学习网</h3>
姓名:
<input type="text" v-model="name">
<br><br>
是否单身:
<input type="checkbox" v-model="isSingle">
<br><br>
<!--
前置理解:
1. name: 给单选框加上 name 属性 可以分组 → 同一组互相会互斥
2. value: 给单选框加上 value 属性,用于提交给后台的数据
结合 Vue 使用 → v-model
-->
性别:
<input v-model="gender" type="radio" name="gender" value="1">男
<input v-model="gender" type="radio" name="gender" value="2">女
<br><br>
<!--
前置理解:
1. option 需要设置 value 值,提交给后台
2. select 的 value 值,关联了选中的 option 的 value 值
结合 Vue 使用 → v-model
-->
所在城市:
<select v-model="cityId">
<option value="101">北京</option>
<option value="102">上海</option>
<option value="103">成都</option>
<option value="104">南京</option>
</select>
<br><br>
自我描述:
<textarea v-model="desc"></textarea>
<button>立即注册</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
name:"",
isSingle:false,
gender:"1",
cityId:"101",
desc:""
}
})
</script>
七、计算属性
1、概念
基于现有的数据,计算出来的新属性。依赖的数据变化,自动重新计算
2、语法
- 声明在computed配置中,一个计算属性对应一个函数
- 使用起来和普通属性一样使用
{{计算属性名}}
computed:{
计算属性名(){
基于现有的数据,编写求值逻辑
return 结果
}
}
3、事例
<style>
table {
border: 1px solid #000;
text-align: center;
width: 240px;
}
th,td {
border: 1px solid #000;
}
h3 {
position: relative;
}
</style>
<div id="app">
<h3>小黑的礼物清单</h3>
<table>
<tr>
<th>名字</th>
<th>数量</th>
</tr>
<tr v-for="(item, index) in list" :key="item.id">
<td>{{ item.name }}</td>
<td>{{ item.num }}个</td>
</tr>
</table>
<!-- 目标:统计求和,求得礼物总数 -->
<p>礼物总数:{{sum}} 个</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
// 现有的数据
list: [
{ id: 1, name: '篮球', num: 1 },
{ id: 2, name: '玩具', num: 2 },
{ id: 3, name: '铅笔', num: 5 },
]
},
computed:{
sum(){
//reduce方法
let total = this.list.reduce((sum,item)=>sum+item.num,0)
return total
}
}
})
</script>
reduce方法
numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0)
- accumulator是累计值
- currentValue是当前值
- accumulator + currentValue是当前值对累计值的操作逻辑,自定义,操作完成后的值重新返回给累计值
- 0是累计值的初始值,自定义
八、computed和methods的区别
methods | computed | |
---|---|---|
作用 | 给实例提供一个方法,调用以处理业务逻辑 | 封装了一段对于数据的处理,求得一个结果 |
语法 | 1.写在methods中 2.作为方法,需要调用—>this.方法名() / {{方法名()}} / @事件名=‘方法名’ | 1.写在computed中 2.作为属性直接使用—>this.计算属性 / {{计算属性名}} |
缓存特性 | 无 | 计算属性会对计算出来的结果缓存,再次使用直接读取缓存,依赖项变化了,会自动重新计算===>并再次缓存 |
九、computed的完整写法
1、语法
computed: {
计算属性名:{
get(){
一段代码逻辑(计算逻辑)
return 结果
}
//修改的值传递给set方法的形参
set(修改的值){
一段代码逻辑(修改逻辑)
}
}
}
set执行时间:一旦计算属性被修改就会执行,且计算属性修改的值传入set形参
get会将返回值作为求值的结果
2、事例
<div id="app">
姓:<input type="text" v-model="firstName"> +
名:<input type="text" v-model="lastName"> =
<span>{{fullname}}</span><br><br>
<button @click="changeName">改名卡</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
firstName: '刘',
lastName: '备',
},
computed: {
fullName:{
get(){
return this.firstName + this.lastName
}
//修改的值传递给set方法的形参
set(value){
this.firstName = value.slice(0,1)
this.lastName = value.slice(1)
}
}
},
methods: {
changeName(){
this.fullName = '吕小布'
}
}
})
</script>
十、成绩案例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.del {
cursor:pointer;
}
</style>
</head>
<body>
<div id="app">
<div class="table">
<table>
<thead>
<tr>编号</tr>
<tr>科目</tr>
<tr>成绩</tr>
<tr>操作</tr>
</thead>
//渲染
<tbody v-if="list.length!==0">
<tr v-for="(item,index) in list" :key="item.id">
<td>{{index+1}}</td>
<td>{{item.subject}}</td>
<td>{{item.score}}</td>
//删除功能
<td @click="del(item.id)" class="del">删除</td>
</tr>
</tbody>
<tbody v-else>
<tr>
<td>暂无数据</td>
</tr>
</tbody>
</table>
</div>
//添加功能
<div class="add">
科目:<input type="text" v-model.trim="subject">
分数:<input type="text" v-model.number="score">
<button @click="add()">添加</button>
</div>
//统计总分平均分,使用计算属性
<div class="show">
总分:<span>{{sum}}</span>
平均分:<span>{{average}}</span>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el:'#app',
data:{
list:[
{id:1,subject:'语文',score:20},
{id:7,subject:'数学',score:90},
{id:12,subject:'英语',score:70}
],
subject:'',
score:'',
},
methods:{
//删除功能函数
del(id){
this.list = this.list.filter((item)=>item.id!==id)
},
//添加功能函数
add(){
this.list.push({
id:+new Date(),
subject:this.subject,
score:this.score
})
}
},
//计算属性
computed:{
sum(){
let total = this.list.reduce((sum,item)=>sum+item.score,0)
return total
},
average(){
let total = this.list.reduce((sum,item)=>sum+item.score,0)
let average = total/this.list.length
return average
}
}
})
</script>
</body>
</html>
十一、watch侦听器
1、语法
作用:监视数据变化,执行一些业务逻辑或者异步操作
语法:
- 简单写法—>简单类型数据,直接监视
data:{
words:'',
obj:{
words:''
}
}
watch:{
数据属性名(newValue,oldValue){
一些业务逻辑或异步操作
},
'对象.属性名'(newValue,oldValue){
一些业务逻辑或异步操作
}
}
- 完整写法—>添加额外配置项
deep:true
对复杂类型进行深度监听immdiate:true
初始化 立刻执行一次
data: {
obj: {
words: '苹果',
lang: 'italy'
},
},
watch: {// watch 完整写法
对象: {
deep: true, // 深度监视
immdiate:true,//立即执行handler函数
handler (newValue) {
console.log(newValue)
}
}
}
十二、Vue生命周期与其四个阶段
1、生命周期
Vue生命周期:就是一个Vue实例从创建到销毁的整个过程。
生命周期四个阶段:① 创建 ② 挂载 ③ 更新 ④ 销毁
- 创建阶段:创建响应式数据
- 挂载阶段:渲染模板
- 更新阶段:修改数据,更新视图
- 销毁阶段:销毁Vue实例
2、钩子函数
Vue生命周期过程中,会自动运行一些函数,被称为【生命周期钩子】→ 让开发者可以在【特定阶段】运行自己的代码
created
钩子函数可以发生初始化渲染请求
mounted
操作dom(此时dom已经渲染完成)
- 创建阶段
beforeCreate
,响应式数据准备好之前created
,响应式数据准备好之后
data:{
count:100
}
beforeCreate(){
console.log(this.count)//输出undefined
}
created(){
console.log(this.count)//输出100
}
- 挂载阶段
beforeMount
,模板渲染之前mounted
,模板渲染之后
<div>{{ title }}</div>
data:{
title:'计数器'
}
beforeMount(){
console.log(document.querySelector(div))//此时页面还未渲染完成,输出{{title}}
},
mounted(){
console.log(document.querySelector(div))//此时页面渲染完成,输出计数器
}
- 更新阶段
beforeUpdate
,页面更新之前(数据修改了,视图还没更新)updated
,页面更新之后(数据修改了,视图更新了)
- 卸载阶段
beforeDestroy
,页面卸载之前destroyed
,页面卸载之后- 并不会将页面内容清除,但是无法操作了
十三、工程化开发和脚手架
1、开发Vue的两种方式
- 核心包传统开发模式:基于html/css/js文件,直接引入核心包,开发Vue
- 工程化开发模式:基于构建工具(如:webpack)的环境中开发Vue
2.脚手架Vue CLI
- 基本介绍
- Vue CLI 是Vue官方提供的一个全局命令工具
- 可以帮助我们快速创建一个开发Vue项目的标准化基础架子。【集成了webpack配置】
- 好处
- 开箱即用,零配置
- 内置babel等工具
- 标准化的webpack配置
- 使用步骤
- 全局安装(只需安装一次即可) yarn global add @vue/cli 或者 npm i @vue/cli -g
- 查看vue/cli版本: vue --version
- 创建项目架子:vue create project-name(项目名不能使用中文)
- 启动项目:yarn serve 或者 npm run serve(命令不固定,找package.json)
3、脚手架目录文件介绍与项目运行流程
(1)目录文件介绍
- main.js文件
此文件的核心作用是:导入App.vue,基于App.vue创建结构渲染index.html
// 导入核心包
import Vue from 'vue'
//导入App.Vue根组件
import App from './App.vue'
//提示:当前处于什么环境(生产环境/开发环境)
Vue.config.productionTip = true/false(true提示,false不提示)
//Vue实例化,提供render方法 基于App.Vue创建结构渲染index.html
new Vue({
render: h => h(App),
//完整写法
render:(createElement)=>{
return createElement(App)
}//箭头函数如果只有一句话可以省略return和花括号
}).$mount('#app')//与el作用一致
4、组件化开发和根组件
- 组件化:一个页面可以拆分成一个个组件,每个组件有着自己独立的结构、样式、行为。
好处:便于维护,利于复用 → 提升开发效率。
组件分类:普通组件、根组件(App.vue)。 - 根组件介
整个应用最上层的组件,包裹所有普通小组件
- App.vue文件的三个组成部分
- template:结构 (有且只能一个根元素)
- script: js逻辑
- style: 样式 (可支持less,需要装包)
- 让组件支持less
(1) style标签,lang=“less” 开启less功能
(2) 装包: yarn add less和less-loader -D 或者 npm i less和less-loader -D
- 让组件支持less
<template>
<div class="App">
</div>
</template>
<script>
//导出的是当前组件的配置项
//里面可以提供data(特殊) methods computed watch 生命周期钩子函数
export default {
created(){
},
...
}
</script>
//让style支持less
<style lang='less'>
.App {
...
}
</style>
5、普通组件的注册使用
组件注册的两种方式
- 局部注册:只能在注册的组件内使用
(1)创建.vue文件(三个组成部分)
(2)在使用的组件内先导入再注册,最后使用
<script>
//导入
import HmHeader from './components/HmHeader.vue'
import HmMain from './components/HmMain.vue'
import HmFooter from './components/HmFooter.vue'
//注册
export default {
components:{
//组件名和组件对象名称相同时可直接简写一个组件名
HmHeader: HmHeader,
HmMain:HmMain,
HmFooter:HmFooter
}
}
</script>
当成html标签使用即可 <组件名></组件名>
- 全局注册:所有组件内都能使用
(1)创建.vue文件(三个组成部分)
(2)main.js中进行全局注册
//导入需要全局注册的组件
import HmButton from './components/HmButton'
//调用Vue.component进行全局注册
//Vue.component('组件名',组件对象)
Vue.component('HmButton',HmButton)
当成html标签使用即可 <组件名></组件名>