VUE
根据官方文档以及网上视频总结的基础vue知识,主要是方便自己查阅,其中包含了一些vue2的语法,以vue3组合式API为主
1 认识Vue
- 无需构建步骤,渐进式增强静态的 HTML
- 在任何页面中作为 Web Components 嵌入
- 单页应用 (SPA)
- 全栈 / 服务端渲染 (SSR)
- Jamstack / 静态站点生成 (SSG)
- 开发桌面端、移动端、WebGL,甚至是命令行终端中的界面
1.1 创建vue项目
1.1 创建项目
vue create 项目名
1.2 运行项目
npm run serve //serve并不是绝对的,具体使用哪个单词从package.json(包描述文件)配置serve的地方
- 当出现命令找不到的时候首先检查
package.json
再检查cmd
运行环境是否在项目之中
1.3 创建项目
注意命令行必须在创建项目的路径下运行 使用以下命令进行切换
cd 项目名称
1.4 打包项目
项目打包时可以删除node_modules文件,可以使用以下命令重新安装
npm install
1.5 使用vite构建项目
vite 是一个轻量级的、速度极快的构建工具,对 Vue SFC 提供第一优先级支持。
npm init vite@latest
1.6 项目结构介绍
-
public: 静态目录一般没操作
-
src:代码开发目录
-
assets:资源目录 图片js css其他资源
-
components:组件目录,搭页面的
-
router:路由 配置项目访问路径使用‘
-
views 所有页面存放目录
-
app.vue 表示项目的主入口,一般无操作
-
main.js 表示vue项目的主配置文件
2 语法和指令
Vue2使用的是选项式API的风格。使用选项式 API,我们可以用包含多个选项的对象来描述组件的逻辑,例如 data
、methods
和 mounted
。选项所定义的属性都会暴露在函数内部的 this
上,它会指向当前的组件实例
<!DOCTYPE html>
<html lang="en">
<head>
<!---省略-->
<script src="vue.js"></script>
<!-- 在浏览器直接复制https://unpkg.com/vue@3.3.4/dist/vue.global.js 然后把内容复制js文件里 -->
</head>
<body>
<div id="box">
{{10+20}}
{{myName}}
<span>{{10+10}}</span>
</div>
<script>
// 指明需要挂载的根节点
// 可以挂载多个根节点
// 动态变量绑定
Vue.createApp({
//es6语法简写
data() {
return {
myName: "1232"//状态
}
}
}).mount("#box")
</script>
</body>
</html>
2.1 模板语法
最基本的数据绑定形式是文本插值,它使用的是“Mustache”语法 (即双大括号):
<span>Message: {{ msg }}</span>
双大括号标签会被替换为相应组件实例中 msg
属性的值。同时每次 msg
属性更改时它也会同步更新。
- 支持三目运算符
{{myName+"aaaa"}}
- 支持三目运算符
{{isLogin?"已登录":"未登录"}}
- 支持调用函数
{{myName.slice(0,1)}}
2.2 指令
2.2.1 v-bind
v-bind所有属性都可以使用进行动态绑定,不操作dom直接改变。可以写字符串拼接,函数以及三目运算符
动态的绑定一个或多个 attribute,也可以是组件的 prop。实现数据的双向绑定
- 缩写:
:
或者.
(当使用.prop
修饰符) - 当用于绑定
class
或style
attribute,v-bind
支持额外的值类型如数组或对象。详见下方的指南链接。
<!-- 绑定 attribute -->
<img v-bind:src="imageSrc" />
<!-- 动态 attribute 名 -->
<button v-bind:[key]="value"></button>
<!-- 缩写 -->
<img :src="imageSrc" />
<!-- 缩写形式的动态 attribute 名 -->
<button :[key]="value"></button>
<!-- 内联字符串拼接 -->
<img :src="'/path/to/images/' + fileName" />
<!-- class 绑定 -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]"></div>
<!-- prop 绑定。“prop” 必须在子组件中已声明。 -->
<MyComponent :prop="someThing" />
v-bind可以绑定一个标签里的多个属性
<img v-bind="imgObj">
//创建一个对象
imgObj: {
//此时的属性必须按照标签里的属性名来写
width: 200,
src://省略
}
2.2.2 disabled陷阱
<button :disabled="isDisabled">click</button>
isDisabled: false
, 此时代表禁用为假
,意思是可以点击,除开false的取值都代表禁用
2.2.3 v-on
v-on:给元素绑定事件监听器。缩写:@
修饰符
.stop
- 调用event.stopPropagation()
。.prevent
- 调用event.preventDefault()
。.capture
- 在捕获模式添加事件监听器。.self
- 只有事件从元素本身发出才触发处理函数。.{keyAlias}
- 只在某些按键下触发处理函数。.once
- 最多触发一次处理函数。.left
- 只在鼠标左键事件触发处理函数。.right
- 只在鼠标右键事件触发处理函数。.middle
- 只在鼠标中键事件触发处理函数。.passive
- 通过{ passive: true }
附加一个 DOM 事件。
<!-- 方法处理函数 -->
<button v-on:click="doThis"></button>
<!-- 动态事件 -->
<button v-on:[event]="doThis"></button>
<!-- 内联声明 -->
<button v-on:click="doThat('hello', $event)"></button>
<!-- 缩写 -->
<button @click="doThis"></button>
<!-- 使用缩写的动态事件 -->
<button @[event]="doThis"></button>
<!-- 停止传播 -->
<button @click.stop="doThis"></button>
<!-- 阻止默认事件 -->
<button @click.prevent="doThis"></button>
<!-- 不带表达式地阻止默认事件 -->
<form @submit.prevent></form>
<!-- 链式调用修饰符 -->
<button @click.stop.prevent="doThis"></button>
<!-- 按键用于 keyAlias 修饰符-->
<input @keyup.enter="onEnter" />
<!-- 点击事件将最多触发一次 -->
<button v-on:click.once="doThis"></button>
<!-- 对象语法 -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
2.2.4 v-if
基于表达式值的真假性,来条件性地渲染元素或者模板片段。当 v-if
元素被触发,元素及其所包含的指令/组件都会销毁和重构。如果初始条件是假,那么其内部的内容根本都不会被渲染。
可用于 <template>
表示仅包含文本或多个元素的条件块。不推荐同时使用v-if
和v-for
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>
使用template
的好处: 可以被它包裹的标签同生共死,而且当条件为真的时候也不占位置
2.2.5 v-show
基于表达式值的真假性,来改变元素的可见性。用法和v-if
一样,不同的是v-show并不会销毁已经创建的节点,底层其实就是添加了css属性display:none
<!-- 会自动添加hidden属性将其隐藏 -->
<div v-show="isShow">我是显示或隐藏</div>
- v-if是真实的按条件渲染,它确保了切换的时候,条件区块内的事件监听器和子组件都会被销毁和重建、
- 同时它也是惰性的,只有条件变成true的时候才被渲染
- v-show无论初始条件如何都会被渲染,只是切换display属性
- 当需要频繁切换的时候使用v-show,如果运行时绑定条件很少改变就使用v-if
2.2.6 v-for
基于原始数据多次渲染元素或模板块。v-for指令可以用于循环接收的后端数据,item是循环变量需见名知意。在vue3里必须指明v-for
的key
值作为唯一标识。
<div v-for="item in items" :key="item.id">
{{ item.text }}
</div>
如果添加index
在数组遍历里是获取数组的下标,在对象中item和index代表对应的键和值。v-for
也支持解构的写法
<div v-for="(item, index) in items"></div>
为什么要指定唯一的key值
Vue默认按照就地更新的策略来更新通过 v-for渲染的元素列表。当数据项的顺序改变时,Vue不会随之移动DOM元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。 为了给Vue一个提示,以便它可以跟踪每个节点的标识,从而重用和重新排序现有的元素,你需要为每个元素对应的块提供一个唯一的key
什么是虚拟dom
是来模拟真实的dom,方便新老虚拟dom进行对比,对比完之后再更新到真实dom中 ,改变数组时根据改变的数组,生成新的虚拟dom树,与老的虚拟dom树进行对比,找出差异,以最小的代价生成一个补丁更新到真实的dom树
2.2.7 v-html
一般来说对于信任的网站可以使用v-html,数据都是由后台提供,如果对于用户提供的数据使用v-html将有可能导致信息泄露等风险 ,所以对于不信任的网站还是使用文本插值来直接显示用户输入的信息
<div v-html="myHtml"></div>
data() {
return {
myHtml: `<h1>你好</h1>`
}
}
3 Style与Class
在处理比较复杂的绑定时,通过拼接生成字符串是麻烦且易出错的。因此,Vue 专门为 class
和 style
的 v-bind
用法提供了特殊的功能增强。除了字符串外,表达式的值也可以是对象或数组**。这样可以避免操作dom从而做到动态的在div上添加样式**
3.1 Class绑定对象
在标签内部也可以写,但是这样太过繁琐,可以直接包装成一个对象进行操作
<div :class="{aaa:true,bbb=false,ccc=true}">赵谦孙俪</div>
<div :class="classObj">赵谦孙俪</div>\
classObj: {
aaa: true,
bbb: true,
ccc: true
},
3.2 Class绑定数组
我们可以给 :class
绑定一个数组来渲染多个 CSS class:
<div :class="[activeClass, errorClass]"></div>
const activeClass = ref('active')
const errorClass = ref('text-danger')
运行结果
<div class="active text-danger"></div>
3.3 Style绑定对象
可以在标签内直接指定样式但是需要进行驼峰命名,要不然就加上''
<div :style="{backgroundColor:'red'}">张三李四</div>
<div :style="{'background-color':'red'}">张三李四</div>
使用状态来动态改变样式
<div :style="styleObj">赵谦孙俪</div>
<div :style="imgObj"></div>
<button @click="click()">click</button>
return {
styleObj: {
backgroundColor: 'red',
ontSize: '20px'
},
imgObj: {
width: "200px",
height: "200px",
backgroundSize: "cover"
}
}
3.4 Style绑定数组
<!-- 方法1:可以在数组里写多个对象 -->
<div :style="[styleObj1,styleObj2]">赵谦孙俪</div>
<!-- 方法2:直接把样式push到数组里 -->
<div :style="styleArr"></div>
<button @click="click()">click</button>
var obj = {
data() {
return {
styleObj1: {
backgroundColor: 'red',
fontSize: '20px'
},
styleObj2: {
backgroundColor: 'yellow'
},
styleArr: [{
width: "200px",
height: "200px",
backgroundSize: "cover"
}]
}
},
methods: {
click() {
//使用push把样式推入到数组中
this.styleArr.push({
// 此时的样式会覆盖上面的样式
width: "300px",
height: "300px",
backgroundImage: "url(https://booklibimg.kfzimg.com/data/book_lib_img_v2/user/0/4e9a/4e9abe6930a0367e3ea18cc3e44dd8d0_0_0_0_0_water.jpg)"
})
}
}
}
4 计算属性
如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。
以下是Vue3的示例:
我们想根据 author
是否已有一些书籍来展示不同的信息:
<template>
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>
</template>
<script setup>
import { reactive, computed } from 'vue'
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
// 一个计算属性 ref
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
</script>
当页面需要多次显示该属性的时候,计算属性就会体现它的优势。计算属性值会基于其响应式依赖被缓存
普通方法的时候则是调用一次就计算一次,使用计算属性会优化性能
4.1 可写计算属性
计算属性默认是只读的。当你尝试修改一个计算属性时,你会收到一个运行时警告。可以通过同时提供 getter 和 setter 来创建
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed({
// getter
get() {
return firstName.value + ' ' + lastName.value
},
// setter
set(newValue) {
// 注意:我们这里使用的是解构赋值语法
[firstName.value, lastName.value] = newValue.split(' ')
}
})
</script>
现在再运行 fullName.value = 'John Doe'
时,setter 会被调用而 firstName
和 lastName
会随之更新。
4.2 计算属性注意事项
Getter 不应有副作用
计算属性的 getter 应只做计算而没有任何其他的副作用,不要在 getter 中做异步请求或者更改 DOM!一个计算属性的声明中描述的是如何根据其他值派生一个值。因此 getter 的职责应该仅为计算和返回该值。
避免直接修改计算属性值
从计算属性返回的值是派生状态。可以把它看作是一个“临时快照”,每当源状态发生变化时,就会创建一个新的快照。更改快照是没有意义的,因此计算属性的返回值应该被视为只读的,并且永远不应该被更改——应该更新它所依赖的源状态以触发新的计算。
5 条件渲染
6 列表渲染
我们可以使用 v-for
指令基于一个数组来渲染一个列表。v-for
指令的值需要使用 item in items
形式的特殊语法,其中 items
是源数据的数组,而 item
是迭代项的别名:
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
<li v-for="item in items">
{{ item.message }}
</li>
在 v-for
块中可以完整地访问父作用域内的属性和变量。v-for
也支持使用可选的第二个参数表示当前项的位置索引。
const parentMessage = ref('Parent')
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
Parent - 0 - Foo
Parent - 1 - Bar
6.1 v-for
与对象
你也可以使用 v-for
来遍历一个对象的所有属性。遍历的顺序会基于对该对象调用 Object.keys()
的返回值来决定。
const myObject = reactive({
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
})
<ul>
<li v-for="value in myObject">
{{ value }}
</li>
</ul>
可以通过提供第二个参数表示属性名 (例如 key):
<li v-for="(value, key) in myObject">
{{ key }}: {{ value }}
</li>
第三个参数表示位置索引:
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>
6.2 数组变化侦听
由于有些数组方法变化的时候vue是侦听不到的,比如map()
和filter()
,所以需要再赋值
7 事件处理
我们可以使用 v-on
指令 (简写为 @
) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:click="handler"
或 @click="handler"
。
事件处理器 (handler) 的值可以是:
- 内联事件处理器:事件被触发时执行的内联 JavaScript 语句 (与
onclick
类似)。 - 方法事件处理器:一个指向组件上定义的方法的属性名或是路径。
<!-- 内联事件处理器 -->
<button @click="count++">add1</button>
<!-- 需要传入参数使用内联中调用函数表达式 ,也能获取event对象-->
<button @click="click1()">add2</button>
<!-- 如果想要获取事件对象(event)方法事件处理器 -->
<button @click="click2">add3</button>
<!-- 传参+获取event -->
<button @click="click3(1,2,3,$event)">click</button>
<!-- 标签里不能写太复杂的语句,只能进行函数调用和函数表达式的书写 -->
<button @click="(evt)=>click4(1,2,3,evt)">click2</button>
7.1 事件修饰符
7.2 按键修饰符
8 表单输入绑定
在前端处理表单时,我们常常需要将表单输入框的内容同步给 JavaScript 中相应的变量。手动连接值绑定和更改事件监听器可能会很麻烦
v-model
指令帮我们简化了这一步骤:
//以前
<input
:value="text"
@input="event => text = event.target.value">
//简化后
<input v-model="text">
注意在 <textarea>
中是不支持插值表达式的。请使用 v-model
来替代:
<!-- 错误 -->
<textarea>{{ text }}</textarea>
<!-- 正确 -->
<textarea v-model="text"></textarea>
- 文本类型的
<input>
和<textarea>
元素会绑定value
property 并侦听input
事件; <input type="checkbox">
和<input type="radio">
会绑定checked
property 并侦听change
事件;<select>
会绑定value
property 并侦听change
事件。- 如果
v-model
表达式的初始值不匹配任何一个选择项,<select>
元素会渲染成一个“未选择”的状态。因此,建议提供一个空值的禁用选项
8.1 表单修饰符
<!-- @change:失去焦点并且内容发生改变的时候才会触发 -->
<input type="text" v-model.lazy="myText">
<!-- .lazy的目的就是减轻浏览器压力,不需要实时改变 -->
<!-- 可以把用户输入的值转换为数字类型的 -->
<input type="text" v-model.number="myNumber">
<!-- input原生表单里如果type为number类型照样是字符串类型 -->
<!-- 在vue里面如果type为number就会自动给v-model加上.number属性 -->
<input type="number" name="" id="" v-model.number="myNumber">
<!-- trim可以去掉前面和后面的空格,防止传入数据库的时候带有空格 -->
<input type="text" v-model.trim="myUsername">
9 监听器
使用watch监听数据什么时候更改,watch可以进行异步,操作dom等行为。 watch适合进行监听,计算属性更适合去获取同步的计算结果,然后把结果返回,并且计算属性还具有依赖缓存
9.1 watch
在vue3中监听器的使用有所不同
//写法一
watch(myText, (newValue, oldValue) => {
console.log("同步/异步", newValue, oldValue);
})
//写法二
watch(() => myText.value, (newValue, oldValue) => {
console.log("同步/异步", newValue, oldValue);
})
//多个数据源监听
watch([myText, select], (newValue, oldValue) => {
console.log("同步/异步", newValue, oldValue);
}, { immediate: true })//我们可以通过传入 immediate: true 选项来强制侦听器的回调立即执行
//deep:true是深度监听,不建议使用,会出现性能问题
//监听reavtive不能直接侦听响应式对象的属性值,需要用一个返回该属性的 getter 函数:
const state = reactive({
myText: ""
})
watch(() => state.myText, (newValue, oldValue) => {
console.log("ajax", newValue, oldValue);
})
9.2 watchEffect
举例使用方法:
// 使用watchEffect
watchEffect(async () => {
// console.log(value);
axios.get(`http://localhost:3000/news?author=${select.value}`).
then(res => {
console.log(res.data);
list.value = res.data
})
})
对于有多个依赖项的侦听器来说,使用 watchEffect()
可以消除手动维护依赖列表的负担。此外,如果需要侦听一个嵌套数据结构中的几个属性,watchEffect()
可能会比深度侦听器更有效,因为它将只跟踪回调中被使用到的属性,而不是递归地跟踪所有的属性。
9.3 watch VS watchEffect
watch
-
具有一定的惰性lazy 第一次页面展示的时候不会执行,只有数据变化的时候才会执行
-
参数可以拿到当前值和原始值
-
可以侦听多个数据的变化,用一个侦听器承载
watchEffect
-
立即执行,没有惰性,页面的首次加载就会执行。
-
自动检测内部代码, 代码中有依赖便会执行
-
不需要传递要侦听的内容会自动感知代码依赖,不需要传递很多参数,只要传递一个回调函数,自动检测参数
-
不能获取之前数据的值只能获取当前值
10 生命周期
Vue3生命周期:组合式 API:生命周期钩子 | Vue.js (vuejs.org)