01. Basis
1.1 概述
💪
@Author
: 天气预报
1.2 项目构建
vue@latest 是官方提供创建 v3 项目的模板,基于 Vite 构建项目
- npm
npm create vue@latest
- 根据脚手架引导安装依赖及环境
Vue.js - The Progressive JavaScript Framework
√ 请输入项目名称: ... chapter-1-1
√ 是否使用 TypeScript 语法? ... 否 / 是
√ 是否启用 JSX 支持? ... 否 / 是
√ 是否引入 Vue Router 进行单页面应用开发? ... 否 / 是
√ 是否引入 Pinia 用于状态管理? ... 否 / 是
√ 是否引入 Vitest 用于单元测试? ... 否 / 是
√ 是否要引入一款端到端(End to End)测试工具? » 不需要
√ 是否引入 ESLint 用于代码质量检测? » 否
正在初始化项目 D:\Code\vue\chapter-1-1...
项目初始化完成,可执行以下命令:
cd chapter-1-1
npm install
npm run dev
- 项目运行
cd <project-name>
npm install
npm run dev
1.3 运行
- 安装依赖 [node_modules]
cd <>
npm i
npm install
- 启动
npm run dev
02. 单文件组件
2.1
2.2
2.3 响应式
当插值表达式内容发生变化时、期望
<template>
HTML 重新渲染则为响应式
- App.vue [非响应式]
<template>
<div> <p>{
{num}}</p>
</div></template>
<script setup>
let num = Math.random();
setInterval(()=>{
num = Math.random()
console.log(num)
}, 1000);
</script>
<style scoped>
h1{
color: pink;
}
</style>
01. ref
-
ref(初始值) 函数包装的变量为响应式变量、该值变更时会触发重新渲染
-
ref() 函数需从 vue 模块导入: import {ref} from ‘vue’
-
aqq.vue []
<script setup>
import {ref} from "vue";
import {v4 as uuid} from 'uuid';
// npm i uuid
// uuid 是一款 uuid 库 v4 是一个 uuid 函数()
const uuidRef = ref(uuid())
setInterval(()=>{
uuidRef.value = uuid()
console.log(uuidRef.value)
}, 1000);
</script>
<template>
<div>
<p>{
{uuidRef}}</p>
</div>
</template>
- app.vue [数组]
const arrayRef = ref([1,2,3]);
setInterval( () => {
arrayRef.value.push(Math.random())
}, 2000);
- App.vue [对象]
<script setup>
import {ref} from "vue";
import {v4 as uuid} from 'uuid';
const userRef = ref({
id: uuid(),
username : 'lsb',
gender : 'gender'
})
setInterval( ()=> userRef.value.id = uuid(), 2000)
</script>
<template>
<div>
<h1>ID:{
{userRef.id}}</h1>
<h1>ID:{
{userRef.username}}</h1>
<h1>ID:{
{userRef.gender}}</h1>
</div>
</template>
总结
- 响应式数据需要使用
ref(初始值)
函数进行包装 - 操作 ref 响应式数据、需以
.value
形式才能访问到具体的值 - 推荐响应式变量 命名为 xxxRef 同时 .value 也可使得敏感响应式变量
注意
xxRef.value 具体值可以进行解构、但解构出的值为只读值、且丢失响应式
- App.vue [对象结构]
<script setup>
import {ref} from "vue";
import {v4 as uuid} from 'uuid';
const userRef = ref({
id: uuid(),
username : 'lsb',
gender : 'gender'
})
setInterval( ()=> userRef.value.id = uuid(), 2000)
const {id, username, gender} = userRef.value;
</script>
<template>
<div>
<h1>ID:{
{userRef.id}}</h1>
<h1>username:{
{userRef.username}}</h1>
<h1>gender:{
{userRef.gender}}</h1>
<p>ID:{
{id}}</p>
<p>username:{
{username}}</p>
<p>gender:{
{gender}}</p>
</div>
</template>
02. reactive
-
reactive(引用类型)
同理 ref 仅能操作对象、数组等引用类型 -
reactive(初始值)
返回的引用可直接操作、无需.value
-
reactive({})
解构操作依然为只读、且丢失响应式 -
App.vue []
<script setup>
import {reactive, ref} from "vue";
import {v4 as uuid} from 'uuid';
const userRea = reactive({
id: uuid(),
username : 'lsb',
gender : 'gender'
})
setInterval( ()=> userRea.id = uuid(), 2000)
const {id, username, gender} = userRea;
</script>
<template>
<div> <h1>{
{userRea}}</h1>
<h1>ID:{
{userRea.id}}</h1>
<h1>username:{
{userRea.username}}</h1>
<h1>gender:{
{userRea.gender}}</h1>
<p>ID:{
{id}}</p>
<p>username:{
{username}}</p>
<p>gender:{
{gender}}</p>
</div></template>
03. toRef
-
toRef( 响应式对象 ,'属性名称')
取出响应式对象中的某个属性、且保持同源 -
响应式对象、取出的响应式属性会联动更新
-
App.vue [ reactive]
<script setup>
import {reactive, ref, toRef, toRefs} from "vue";
import {v4 as uuid} from 'uuid';
const user = reactive({
id: uuid(),
username : 'lsb',
gender : 'gender'
})
const {id, username, gender} = user;
const idRef = toRef(user, 'id');
setInterval( ()=> user.id = uuid(), 2000)
// setInterval( ()=> idRef.value = uuid(), 2000)
</script>
<template>
<div> <h1>user:{
{user}}</h1>
<h1>idRef:{
{idRef}}</h1>
<h1>解构:{
{id}}</h1>
</div></template>
- App.vue [ ref响应式对象 ]
- 记得加
.value
<script setup>
import {reactive, ref, toRef, toRefs} from "vue";
import {v4 as uuid} from 'uuid';
const people = ref({
id: uuid()
})
const peopleIDRef = toRef(people.value , 'id')
// setInterval( ()=> people.value.id = uuid(), 2000)
setInterval( ()=> peopleIDRef.value = uuid(), 2000)
</script>
<template>
<div> <h1>people:{
{people}}</h1>
<h1>peopleIDRef:{
{peopleIDRef}}</h1>
</div>
</template>
04. toRefs
-
toRefs(响应式对象)
将参数转为普通对象、但该对象的每个属性指向响应式对象属性 -
响应式对象会影响普通对象, 反之,不行
-
App.vue
<script setup>
import {reactive, ref, toRef, toRefs} from "vue";
import {v4 as uuid} from 'uuid';
const user = reactive({
id: uuid(),
username : 'lsb',
gender : 'gender'
})
const ordinaryUser = toRefs(user);
setInterval( () =>{
user.id = uuid()
ordinaryUser.username = toRef('frank')
}, 1000)
</script>
<template>
<div>
<h1>user{
{user}}</h1>
<h1>ordinaryUser{
{ordinaryUser}}</h1>
</div>
</template>
- App.vue [解构]
<script setup>
import {reactive, ref, toRef, toRefs} from "vue";
import {v4 as uuid} from 'uuid';
const user = reactive({
id: uuid(),
username : 'lsb',
gender : 'gender'
})
const ordinaryUser = toRefs(user);
let {id , username} = toRefs(user);
setInterval( () =>{
// user.id = uuid()
// ordinaryUser.username = toRef('frank')
id = uuid()
}, 1000)
</script>
<template>
<div> <h1>user{
{user}}</h1>
<h1>ordinaryUser{
{ordinaryUser}}</h1>
<h1>解构:{
{username}}</h1>
<h1>解构:{
{id}}</h1>
</div></template>
05. readonly
-
readonly(普通对象或变量|响应式|ref)
返回原值的只读代理 -
App.vue [ ]
<script setup>
import {reactive, ref, toRef, toRefs, readonly} from "vue";
import {v4 as uuid} from 'uuid';
const user = reactive({
id: uuid(),
username : 'lsb',
gender : 'gender'
})
let readonlyUser = readonly(user)
user.username = "FRANK"
readonlyUser.username = "BL";
// Attempt to assign to const or readonly variable
</script>
<template>
<div> <h1>{
{user.username}}</h1>
<h1>{
{user}}</h1>
</div></template>
- App.vue [ ]
<script setup>
import {reactive, ref, toRef, toRefs, readonly} from "vue";
import {v4 as uuid} from 'uuid';
const user = readonly({
id: uuid(),
username : 'lsb',
gender : 'gender'
})
user.username = "BL";
// Attempt to assign to const or readonly variable
</script>
<template>
<div> <h1>{
{user.username}}</h1>
<h1>{
{user}}</h1>
</div></template>
06. isRef
-
isRef(变量)
判断参数变量是否为ref
-
isReactive(变量)
判断参数变量是否为reactive
-
App.vue [判断是否被修饰过]
<script setup>
import {reactive, ref, toRef, toRefs, readonly, isRef, isReactive} from "vue";
import {v4 as uuid} from 'uuid';
const user = ref({
id: uuid(),
username : 'lsb',
gender : 'gender'
})
const num = ref(Math.random())
const isRef1 = isRef(num) // true
const isRef2 = isReactive(user) // false
</script>
<template>
<div> <h1>{
{user}}</h1>
<h1>{
{isRef1}}</h1>
<h1>{
{isRef2}}</h1>
</div></template>
- App.vue [ 问题 ]
{ {}}
被直接vue解析 , 不能再通过JS检验isRef
<script setup>
import {reactive, ref, toRef, toRefs, readonly, isRef, isReactive} from "vue";
import {v4 as uuid} from 'uuid';
const user = ref({
id: uuid(),
username : 'lsb',
gender : 'gender'
})
const num = ref(Math.random())
const isRef1 = isRef(num) // true
const isRef2 = isReactive(user) // false
</script>
<template>
<div> <h1>{
{user}}</h1>
<h1>{
{isRef1}}</h1>
<h1>{
{isRef2}}</h1>
<h1>{
{isRef(num)}}</h1> <!-- false-->
</div></template>
07. isReadonly
-
检查传入的值是否为只读对象
-
注意: 不能通过传入的对象直接赋值、只读对象的属性也不能更改
-
App.vue [ ]
<script setup>
import {reactive, ref, toRef, toRefs, readonly, isRef, isReactive, isReadonly} from "vue";
import {v4 as uuid} from 'uuid';
const user = readonly({
id: uuid(),
username : 'lsb',
gender : 'gender'
})
console.log(isReadonly(user)) // true
user.username = "FRANK" // Attempt to assign to const or readonly variable
console.log(user)
</script>
<template>
<div> <h1>{
{'iSREADONLY'}}</h1>
<h1>{
{user}}</h1>
</div>
</template>
- App.vue [ ]
08. unRef
-
返回
unRef(参数是普值返回本身 | 参数是 ref 返回 ref.value)
-
App.vue [ ]
<script setup>
import {reactive, ref, toRef, toRefs, readonly, isRef, isReactive, isReadonly,unref,shallowRef} from "vue";
import {v4 as uuid} from 'uuid';
const numberRef = ref(100)
setInterval( ()=> numberRef.value = Math.random(), 1000)
const value = unref(numberRef)
console.log("numberRef:",numberRef)
console.log('----')
// const value = isRef(numberRef)? numberRef.value : numberRef
// console.log(value) 100
</script>
<template>
<div>
<h1>{
{'UNREF'}}</h1>
<h1>{
{value}}</h1>
<h1>{
{numberRef}}</h1>
</div>
</template>
09. shallowRef
-
与 ref 不同、shallowRef 是浅层响应式、只对
.value
响应式 -
const user = shallowRef({name:'lucas'})
-
user.value = {}
是响应式、user.value.name = ''
不是响应式 -
App.vue [ ]
<script setup>
import {reactive, ref, toRef, toRefs, readonly, isRef, isReactive, isReadonly,unref,shallowRef} from "vue";
import {v4 as uuid} from 'uuid';
const student = shallowRef({
id : uuid(),
stuname : "LSB"
})
setInterval( ()=>student.value.id = uuid(),1000 ) // 不变
setInterval( ()=>student.value ={id:uuid(), stuname: "FRANK"},1000 ) // 变
</script>
<template>
<div>
<h1>{
{'shallowRef'}}</h1>
<h1>{
{student}}</h1>
</div>
</template>
2.4 计算属性
计算属性用于缓存计算结果、且完成计算逻辑封装[通常是计算响应式数据]
-
computed(有返回值的函数) computed 会返回一个只读的 ref 引用
-
computed 返回的值被 vue 称为计算属性
-
注意: 计算属性是带有响应式数据源追踪的
-
App.vue [ ]
<script setup>
import {v4 as uuid} from 'uuid';
import {ref, computed} from "vue";
const counter = ref(100)
// 1. 缓存计算结果
// 2. 带有响应式数据追踪
// 3. computed 用于完成业务数据的计算
const doubleCounter = computed(()=>{
console.log("...")
return counter.value * 2
})
</script>
<template>
<div> <h1>{
{'computed'}}</h1>
<h1>:computed{
{doubleCounter}}</h1>
<h1>:computed{
{doubleCounter}}</h1>
<h1>:computed{
{}}</h1>
</div>
</template>
- App.vue [ 用于完成业务数据的计算 ]
<script setup>
import {v4 as uuid} from 'uuid';
import {ref, computed} from "vue";
// 3. computed 用于完成业务数据的计算
const one = ref(10)
const two = ref(20)
const sum = computed(()=>one.value+two.value)
</script>
<template>
<div> <h1>{
{'computed'}}</h1>
<h1>:computed{
{sum}}</h1>
</div></template>
2.5 响应式监听
如果期望对响应式变量值发生改变时、作出逻辑操作、即可监听响应式变量
01. watch
-
侦听 当前组件 一个或多个响应式数据源、并在数据源变化时调用所给的回调函数
-
执行次数: 0 ~ N
-
注意 watch 也可在子组件中 监听父组件传递过来的响应式
-
App.vue [ ]
<script setup>
import {v4 as uuid} from 'uuid';
import {ref, watch} from "vue";
const numberRedf =ref(Math.random())
setInterval(()=>{
return numberRedf.value = Math.random()
}, 1000)
// 希望numberRef 变化 执行行的操作
watch(numberRedf, ()=> {
console.log("...")
})
</script>
<template>
<div> <h1>{
{'watch'}}</h1>
<h1>{
{numberRedf}}</h1>
</div>
</template>
- App.vue [ 回调函数给予参数 ]
- 对新旧值 敏感
<script setup>
import {v4 as uuid} from 'uuid';
import {ref, watch} from "vue";
const numberRedf =ref(199)
setInterval(()=>{
return numberRedf.value = Math.random()
}, 3000)
// 希望numberRef 变化 执行行的操作
watch(numberRedf, (_newValue, _oldValue)=> {
console.log(_newValue, _oldValue)
console.log("...")
})
</script>
<template>
<div> <h1>{
{'watch'}}</h1>
<h1>{
{numberRedf}}</h1>
</div>
</template>
02. watchEffect
-
立即运行 watchEffect 参数函数且响应式地追踪其依赖、并在依赖更新时再次执行
-
watchEffect 执行次数: 1 ~ N
-
watchEffect 内部若操作响应式数据源且变更时、还会触发执行
-
App.vue [ ]
<script setup>
import {v4 as uuid} from 'uuid';
import {ref, watch, watchEffect} from "vue";
const ageRef = ref(10)
watchEffect(()=>{
// 数据请求
console.log("I EXECUTE")
console.log(ageRef.value)
})
setInterval(()=>ageRef.value=uuid(), 2000)
</script>
<template>
<div>
<h1>{
{'watchEffect'}}</h1>
<h1>{
{ageRef}}</h1>
</div>
</template>
2.6 指令
指令是 Vue 特有且针对 template HTML 渲染行为的预定属性
名称 | 类型 | |
---|---|---|
v-text | 文本渲染 | |
v-html | 文本渲染 | |
v-show | 控制元素显示、隐藏 | |
v-if | 控制元素显示、隐藏 | |
v-for | 遍历结构 | |
v-bind | 绑定HTML 元素属性、自定义属性 | |
v-on | 绑定时间 :点击 | @ |
v-model | 输入框 | |
v-pre | ||
自定义属性 |
01. v-text
v-text 绑定文本、绑定 HTML 元素不能有文本内容
- App.vue [ ]
<script setup>
const username = "LSB"
</script>
<template>
<div>
<h1>username:{
{username}}</h1>
<h2 v-text="username"></h2>
<!-- 不能和拼接其他静态文体-->
</div>
</template>
02. v-html
v-html 绑定文本、内容中 HTML 元素会被渲染
- App.vue [ ]
<script setup>
const html = '<i>iELEMENT</i>'
</script>
<template>
<div>
<h1>{
{html}}</h1>
<h1 v-html="html"></h1>
</div>
</template>
03. v-show
v-show 以 css display: none 方式控制元素是否显式
- App.vue [ ]
<script setup>
const show = true
</script>
<template>
<div>
<h1>{
{html}}</h1>
<div v-show="show">
<p>SHOW THIS TEXT</p>
</div>
</div>
</template>
04. v-if
v-if 以 dom 移除/添加 方式控制元素是否显式
-
v-if 以 dom 移除/添加 方式控制元素是否显式
-
v-if / 还可配合 v-else 一起使用、但 v-else 必须 紧贴上一个 v-if
-
App.vue [ ]
-
打开调试工具~
<script setup>
const show = 0
</script>
<template>
<div>
<h1>{
{html}}</h1>
<div v-if="show">
<p>SHOW THIS TEXT</p>
</div> <div v-else>
<h1>ELSE SHOW THIS TEXT</h1>
</div>
</div>
</template>
05. v-for
v-for 遍历生成 HTML 结构、v-for 写在刚好每次都要生成结构的主元素上
-
:key
是 vue 内部属性 用于为每次循序结构绑定唯一值、避免重复渲染 -
App.vue [ ]
<script setup>
const array = ['a', 'b','c','d']
</script>
<template>
<div>
<ul>
<li v-for="(e,i) in array" :key="e">{
{e}}</li>
</ul>
<ul>
<li v-for="num in 10" :key="num">{
{num}}</li>
</ul>
</div>
</template>
- App.vue [ 遍历对象 ]
<script setup>
const userList = [
{
id:1,username :'LSB'
},
{
id:2,username : "U"
},
{
id:3,username: "X"
}
]
</script>
<template>
<ul><!-- <li v-for="user in userList" :key="user.id">-->
<li v-for="(user,index) in userList" :key="index">
<p>{
{user.username}}-{
{index}}</p>
</li> </ul>
</template>
- App.vue [ 对象解构 ]
<script setup>
const userList = [
{
id:1,username :'LSB'
},
{
id:2,username : "U"
},
{
id:3,username: "X"
}
]
</script>
<template>
<ul>
<li v-for="({id, username},index) in userList" :key="index">
<p>{
{username}}-{
{index}}-{
{id}}</p>
</li>
</ul>
</template>
06. v-bind
v-bind 用于绑定 HTML 元素属性、自定义属性也可
-
v-bind:属性名称="变量"
也可简写为:属性名称="变量"
-
App.vue [ ]
<script setup>
const url = "http://LSBZUISHAI.com"
</script>
<template>
<div>
<h1>
<a v-bind:href="url">asd</a>
<a :href="url">|asd</a>
</h1>
</div>
</template>
07. v-on
v-on 用于绑定 javascript 原生事件、或自定义事件
-
v-on:事件名称="处理函数"
也可简写为@事件名称.修饰符="处理函数
-
App.vue [ ]
<script setup>
import {ref} from "vue";
const counter = ref(1)
function incr(){
counter.value++
}
</script>
<template>
<div>
<h1>counter:{
{counter}}</h1>
<h1><button v-on:click="incr">BUTTON1</button></h1>
<h1><button @:click="incr">BUTTON2</button></h1>
</div>
</template>
- App.vue [ $event 事件对象]
<script setup>
import {ref} from "vue";
const counter = ref(1)
function incr(){
counter.value++
}
function handleClick(e, event){
console.log(e)
console.log("---")
console.log(event)
}
</script>
<template>
<div>
<!-- $event 事件对象 PointerEvent--> <h1><button v-on:click="handleClick(100, $event)">BUTTON</button></h1>
</div>
</template>
08. v-model
v-model 针对 input/select/textarea 的双向绑定指令
-
v-modle 绑定 input、textarea [input事件]
-
v-modle 绑定 select [change事件]
-
App.vue [ ]
<script setup>
import {ref} from 'vue'
const keyword = ref('INPUT')
</script>
<template>
<h1>{
{keyword}}</h1>
<input type="text" v-model="keyword">
</template>
- App.vue [ 下拉列表 ]
<script setup>
import {ref} from 'vue'
const gender = ref('MAN')
</script>
<template>
<h1>{
{gender}}</h1>
<select v-model="gender">
<option value="male">MAN</option>
<option value="female">WOMEN</option>
</select>
</template>
- App.vue [ 单选框 ]
<script setup>
import {ref} from 'vue'
const sex = ref('SEX')
</script>
<template>
<h1>单选框-{
{sex}}</h1>
<input type="radio" name="sex" v-model="sex" value="MAN">MAN
<input type="radio" name="sex" v-model="sex" value="WOMEN">WOMEN
</template>
09. v-pre
v-pre 作用元素内部的 { {}} 不会被渲染
- App.vue [ 不会被渲染 ]
<script setup>
import {ref} from 'vue'
const usernameRef = ref('FRANK')
const age = ref('12')
const LSB = 666
</script>
<template>
<h1 v-pre>{
{usernameRef}}</h1>
<h1 v-pre>{
{age}}</h1>
<h1 v-pre>{
{LSB}}</h1>
</template>
10. 第三方指令
@formkit/auto-animate 可实现子元素变动动画[删除、添加、移动]
- NPM
npm @formkit/auto-animate
- main.js [ 挂载 ]
import {
createApp } from 'vue'
import App from './App.vue'
import {
autoAnimatePlugin} from "@formkit/auto-animate/vue";
const app = createApp(App);
app.use(autoAnimatePlugin)
app.mount('#app')
- App.vue [ 删除动画 ]
<script setup>
import {ref} from 'vue'
const emojiSet = ref(new Set(['😊','🤣','😘','😁','😎']))
function remove(emoji){
emojiSet.value.delete(emoji)
}
</script>
<template>
<ul v-auto-animate>
<li v-for="(emoji, i) in emojiSet" :key="i" @click="remove(emoji)">
{
{emoji}}-{
{i}}
</li>
</ul>
</template>
2.7 事件修饰符
事件修饰符是 vue 对事件对象轻微处理、通过预制修饰符处理 event 对象
- 部分修饰符可组合使用、但多个修饰符有时可能需注意使用顺序
- 使用方式
<a @click.prevent="handleClick">
表示阻止超链接默认行为
01. 点击时间修饰符
.stop | |
.prevent | 阻止事件向上冒泡 |
.self | |
.capture | |
.once | 只能执行一次 |
.passive |
- App.vue [ ]
<script setup>
function handleClick(){
console.log('CLICK')
}
function fun1(){
console.log("FUN1")
}
function fun2(){
console.log("FUN2")
}
</script>
<template>
<h1><button @click.once="handleClick">button</button></h1>
<!-- prevent 不执行跳转 -->
<h1><a href="https://jd.com" @click.prevent="handleClick">JD</a></h1>
<!-- stop 阻止事件向上冒泡 -->
<div style="background-color: pink" @click="fun1">
BUTTON1
<button @click.stop="fun2">BUTTON2</button>
</div>
</template>
02. 按键修饰符
.enter | |
.tab | |
.delete | |
.esc | |
.space | |
.up | |
.down | |
.left | |
.right |
- App.vue [ ]
03. 鼠标按键修饰符
.left | |
.right | |
.middle | |
04. 输入框修饰符
.lazy | |
.number | |
.trim | 去除空格 |
- App.vue [ ]
<script setup>
import {ref} from "vue";
function input(){
console.log('ENTER')
}
const one = ref('')
const two = ref('')
</script>
<template>
<!-- 相当于 实现了 e.key==='Enter'--> <div style="background-color: pink;padding: 50px">
<input type="text" @keyup.enter = "input">
</div><!-- lazy -->
<h1>SUM={
{one+two}}</h1>
<input type="text" v-model.lazy.trim.number="one"></input>
<input type="text" v-model.trim.number="two"></input>
</temp