vue3的学习
vue3的学习的话,我们的学习的思路就是使用我们的那个ts的编码格式的使用
vue3的编码的风格:我们是可以实现后面的那个选项式的编码格式和组合式的编码格式
vue3的项目的创建
使用vite来创建vue3项目
// 创建指令
npm create vue@latest
// 然后的下面的就是一些问答样式的创建项目了
npm install
// 通过这个就可以实现基本那个安装所有的那个依赖
// 我们准备将那个项目进行发布的时候,就可以使用最后的那个指令来进行
npm run build
// 通过这个就是可以实习那一个那个./dist里面了
public:我们每一个页签图标都是放在的后面的那个public目录中的
src 就是我们的源码的所在地
index.html 就是我们的入口文件
vite.config.ts就是我们的整个项目的配置文件
src目录的结构
开始对我们的那个src里面的结构进行剖析
首先我们的src中的结构就是从我们的那个main.ts中进行引入的
App.vue就是我们的那个根组件,所有的那个都是在我们的那个里面进行的引入
我们在那个main.ts实现的是一些路由的配置或者说是一些那个组件/路由/pinia状态管理等的配置
我们使用那个createApp来实现创建我们的app的平台
然后后面的就是通过app这个来实现使用这些路由/pinia/app.vue
main.ts结构
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')
index.html结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
index.html ----- 寻找我们的那个main.ts ---- 寻找路由设置/App.vue/pinia配置
components目录
这个目录中存放的就是我们的写的那个组件,后面的实现就是导入我们的那个App.vue中进行显示
assets目录
就是用于存放一些固有的CSS
router目录
就是用于进行我们的那个路由的配置文件
实现App.vue
<script lang="ts" setup>
//js或者ts源码
</script>
<template>
<!--用于书写我们的html结构-->
<person/>
</template>
<style>
/* 样式的设计 */
</style>
首先的话,我们的vue2是那个选项式的编码风格
vue3的那个编码是可以支持选项式的编码格式,但是我们的那个只主要支持的是组合式的编码风格
组件的书写格式
选项式的写法
<script lang="ts">
// 开始我们的那个选项式的写法
export default {
data(){
return{
a:10,
b: this.name
}
},
setup(){
// 数据
let name = "张三";
// 方法
function changename(){
name = "zhang_shan"
}
return {name, changename} // 最后我们还要进行返回后面的那个数据
}
}
</script>
<template>
<div>你好呀</div>
<div>{{ name }}</div>
<button @click="changename">按钮</button>
<!--注意我们的这里面的数据不是那个响应式的数据,所以说,后面的我们学习是不可以实现数据的更新的-->
</template>
<style scoped>
</style>
注意:我们的选项式的data中是可以读取得到我们的那个setup中的数据的
但是我们的那个中不可以读取得到data中的数据的
组合式的api是不会实现那个基本的读取得到后面的那个的,就是简化了this的使用
组合式的写法
这个的话,就是实现我们的那个setup的语法糖
使用了,这个语法糖之后,我们的那个实现的效果就是定义数据和暴露数据两个步骤都执行了
<script lang="ts" setup>
// 开始我们的那个选项式的写法
// 数据
let name = "张三";
// 方法
function changename(){
name = "zhang_shan"
}
</script>
<!--注意我们的平时是含有两个的script的,一个用来定义我们的那个组件名,一个用来进行写入方法-->
<script lang="ts">
export default{
name = "Person";
// 所以说我们的组件名是Person
}
</script>
<template>
<div>你好呀</div>
<div>{{ name }}</div>
<button @click="changename">按钮</button>
</template>
<style scoped>
</style>
由于这个写法过于复杂,所以说我们是可以实现基本的简化的
就是安装插件 vite-plugin-vue-setup-extend,然后在我们的那个vite.config.ts中进行配置即可
<script lang="ts" setup name="Person">
// 开始我们的那个选项式的写法
// 数据
let name = "张三";
// 方法
function changename(){
name = "zhang_shan"
}
// 这种方法的使用,和我们的上面的那个等效
</script>
<template>
<div>你好呀</div>
<div>{{ name }}</div>
<button @click="changename">按钮</button>
</template>
<style scoped>
</style>
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import vueDevTools from 'vite-plugin-vue-devtools'
import vitePlugin from 'vite-plugin-vue-setup-extend'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
vueJsx(),
vueDevTools(),
vitePlugin()
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
vue3的响应式数据
ref创建基本类型的响应式数据
// 注意我们使用的时候,我们需要做的就是执行那个导入
import {ref} from "vue"
// 使用的方法:就是我们的那个数据是响应式数据,那么那个数据就使用ref来进行包裹
let name = "张三";
// 我们为了这个name是那个响应式数据,那么我们就是实现基本的那个使用ref包裹
let name = ref("张三");
<script lang="ts" setup>
import {ref} from "vue"
// 开始我们的那个选项式的写法
// 数据
let name = ref("张三")
// 方法
function changename(){
name.value = "zhang-san"
}
</script>
<template>
<div>你好呀</div>
<div>{{ name }}</div>
<button @click="changename">按钮</button>
</template>
<style scoped>
</style>
reactive创建对象类型的响应式数据
注意我们的这个数据的话实际上是一个深层次的
// 首先先导入
import {reactive} from "vue"
<script lang="ts" setup>
import {ref, reactive} from "vue"
// 开始我们的那个选项式的写法
// 数据
let name = ref("张三")
let car = reactive({name:"奔驰", pricy:1000})
// 方法
function changename(){
name.value = "zhang-san"
console.log(name)
}
// 修改汽车的名字
function changecarname(){
car.name = "宝马"
}
// 修改汽车的价格
function changecarpricy(){
car.pricy = 10000
}
</script>
<template>
<div>你好呀</div>
<div>{{ name }}</div>
<div>{{ car.name }}-{{car.pricy}}</div>
<button @click="changename">按钮</button>
<button @click="changecarname">修改汽车的名称</button>
<button @click="changecarpricy">修改汽车的价格</button>
</template>
<style scoped>
</style>
ref:可以定义那个基本的响应式数据和对象类型的响应式数据,这个默认的不是那个深层次的
reactive:只可以用来定义那个对象类型的响应式数据,但是默认的是深层次的
ref定义对象类型的响应式数据
<script lang="ts" setup>
import {ref} from "vue"
// 开始我们的那个选项式的写法
// 数据
let name = ref("张三")
let car = ref({name:"奔驰", pricy:1000})
let student = ref([
{name:"老鞠", age:10},
{name:"老胡", age:20}
])
// 方法
function changename(){
name.value = "zhang-san"
console.log(name)
}
// 修改汽车的名字
function changecarname(){
car.value.name = "宝马"
}
// 修改汽车的价格
function changecarpricy(){
car.value.pricy = 10000
}
function changestudent(){
student.value[0].age = 20;
}
</script>
<template>
<div>你好呀</div>
<div>{{ name }}</div>
<div>{{ car.name }}-{{car.pricy}}</div>
<div>{{ student[0].age }}</div>
<button @click="changename">按钮</button>
<button @click="changecarname">修改汽车的名称</button>
<button @click="changecarpricy">修改汽车的价格</button>
<button @click="changestudent">修改学生年纪</button>
</template>
<style scoped>
</style>
ref和reactive对比
ref的数据的响应式的修改的时候,我们需要使用那个.value来实现触碰到我们的数据
reactive是默认的那个深层次的,重新那个对象后,就会直接失去响应式,如果想要进行那个修改,那么我们就要使用
Object.assign(对象1,对象2)
这个时候实现的就是那个将对象2到对象1中,重新分配
<script lang="ts" setup>
import { reactive, ref } from 'vue'
// 开始我们的那个选项式的写法
// 数据
let name = ref("张三")
let car = reactive({name:"奔驰", pricy:1000})
let student = ref([
{name:"老鞠", age:10},
{name:"老胡", age:20}
])
// 方法
function changename(){
name.value = "zhang-san"
console.log(name)
}
// 修改汽车的名字
function changecarname(){
car.name = "宝马"
}
// 修改汽车的价格
function changecarpricy(){
car.value.pricy = 10000
}
function changestudent(){
student.value[0].age = 20;
}
function changecar(){
Object.assign(car, {name:"宝马", pricy:100000}); //重要
}
</script>
<template>
<div>你好呀</div>
<div>{{ name }}</div>
<div>{{ car.name }}-{{car.pricy}}</div>
<div>{{ student[0].age }}</div>
<button @click="changename">按钮</button>
<button @click="changecarname">修改汽车的名称</button>
<button @click="changecarpricy">修改汽车的价格</button>
<button @click="changestudent">修改学生年纪</button>
<button @click="changecar">修改汽车</button>
</template>
<style scoped>
</style>
toRef和toRefs的使用
我们使用这个东西的时候,首先先进行的是那个先进行导入即可
这个的玩意就是来解决我们的那个解构赋值的缺陷,实现基本转化为后面的ref对象
<script lang="ts" setup>
import { reactive, ref, toRefs } from 'vue'
// 开始我们的那个选项式的写法
// 数据
let nam = ref("张三")
let car = reactive({name:"奔驰", pricy:1000})
let student = ref([
{name:"老鞠", age:10},
{name:"老胡", age:20}
])
// 方法
let {name, pricy} = toRefs(car);
function changename(){
nam.value = "zhang-san"
console.log(name)
}
// 修改汽车的名字
function changecarname(){
car.name = "宝马"
}
// 修改汽车的价格
function changecarpricy(){
car.pricy = 10000
}
function changestudent(){
student.value[0].age = 20;
}
function changecar(){
Object.assign(car, {name:"宝马", pricy:100000})
}
// 开始修改我们的那个汽车的数据
function changecarName(){
name.value += "~"
}
</script>
<template>
<div>你好呀</div>
<div>{{ nam }}</div>
<div>{{ car.name }}-{{car.pricy}}</div>
<div>{{ student[0].age }}</div>
<button @click="changename">按钮</button>
<button @click="changecarname">修改汽车的名称</button>
<button @click="changecarpricy">修改汽车的价格</button>
<button @click="changestudent">修改学生年纪</button>
<button @click="changecar">修改汽车</button>
<button @click="changecarName">修改</button>
</template>
<style scoped>
</style>
标签中的ref属性
<script lang="ts" setup name="Person">
// 开始实现我们的出现那个h2标签的内容。我们开始使用DOM原生的操作来实现
function show(){
console.log(document.getElementById("title2").innerText);
let title = document.getElementById("title2");
document.write(title.innerText);
}
</script>
<template>
<div>
<h1>重庆邮电大学</h1>
<h2 id="title2">蓝山工作室</h2>
<h3>前端vue组</h3>
<button @click="show">点击显示h2的内容</button>
</div>
</template>
<style scoped>
</style>
<!--现在的话,我们不适用原生的原因就是,我们在那个协同开发的时候,可能两个组件中的id值相同,就可能导致最后的那个项目的不同
就有可能导致那个得到的不是我们想要的
因为我们的最后的页面是进行那个杂糅在一起的
我们的后面是可以使用我们的ref来解决这个冲突的
->
ref的使用就是相当于打结点,来实现基本的识别
<script lang="ts" setup name="Person">
import {ref} from "vue"
// 创建容器
let title2 = ref() // 用于实现存储使用ref标记的内容
function show(){
console.log(title2.value)
}
</script>
<template>
<div>
<h1>重庆邮电大学</h1>
<!--就是实现的那个标记-->
<h2 ref="title2">蓝山工作室</h2>
<h3>前端vue组</h3>
<button @click="show">点击显示h2的内容</button>
</div>
</template>
<style scoped>
</style>
注意我们的上面的实现的都是使用我们的那个ref的添加是在我们的那个heml标签中的
我们还是可以可添加到组件标签中的
App.vue
<script lang="ts" setup name="App">
//js或者ts源码
import person from "./components/Person.vue"
import {ref} from "vue"
let ren = ref();
function showRen(){
console.log(ren.value)
}
</script>
<template>
<!--用于书写我们的html结构-->
<person ref="ren"/>
<button @click="showRen">显示组件的信息</button>
</template>
<style>
/* 样式的设计 */
</style>
Person.vue
<script lang="ts" setup name="Person">
import {ref, defineExpose} from "vue"
// 创建容器
let title2 = ref() // 用于实现存储使用ref标记的内容
let a = ref(1);
let b = ref(2);
let c = ref(3);
function show(){
console.log(title2.value)
}
// 我们在这里面暴露什么,我们就可以实现App中的ref就得到什么
defineExpose({a, b, c})
</script>
<template>
<div>
<h1>重庆邮电大学</h1>
<!--就是实现的那个标记-->
<h2 ref="title2">蓝山工作室</h2>
<h3>前端vue组</h3>
<button @click="show">点击显示h2的内容</button>
</div>
</template>
<style scoped>
</style>
vue3的计算属性
设置可读可写的数据
这个的实现的效果就是实现的我们的输入名字的首位和那个后面的时候,我们的名字就是什么
同时我们的那个为名字是什么的时候,我们的对应的位置就是什么内容
<script lang="ts" setup>
import { compile, computed, reactive, ref, toRefs } from 'vue'
// 开始准备数据
let firstName = ref("");
let lastName = ref("");
// 开始实现基本的算法问题 计算属性
let fullName = computed(
{
// 开始实现我们的可读可写的数据
get(){
if (firstName.value.slice(0,1).match(/[a-z]/)){
return firstName.value.slice(0,1)[0].toUpperCase() +
firstName.value.slice(1).toLowerCase() + "-" +
lastName.value;
}
else if(firstName.value.slice(0,1).match(/[A-Z]/)){
return firstName.value.slice(0,1)[0] + firstName.value.slice(1).toLowerCase() + "-" + lastName.value;
}
else{
return firstName.value + "-" + lastName.value;
}
},
/*
set(){
// 开始将我们的数据返回给页面
firstName.value = fullName.value.split("-")[0];
lastName.value = fullName.value.split("-")[1];
}
*/
set(val){
// 开始将我们的数据返回给页面
firstName.value = val.split("-")[0];
lastName.value = val.split("-")[1];
}
}
)
</script>
<template>
<div>
<!--我们的v-model就是实现的页面中的数据和实际的进行的双向的绑定-->
<label for="firstName">姓:</label><input type="text" id="firstName" v-model="firstName"><br>
<label for="lastName">名:</label><input type="text" id="lastName" v-model="lastName"><br>
全名:<span>{{ fullName }}</span>
</div>
</template>
<style scoped>
</style>
设置只可读的方法
<script lang="ts" setup>
import { compile, computed, reactive, ref, toRefs } from 'vue'
// 开始准备数据
let firstName = ref("");
let lastName = ref("");
// 开始实现基本的算法问题 计算属性
let fullName = computed(
()=>{
// 我们通过发现可以知道,我们在计算属性中返回什么,就会出现什么数据
if (firstName.value.slice(0,1).match(/[a-z]/)){
return firstName.value.slice(0,1)[0].toUpperCase() +
firstName.value.slice(1).toLowerCase() + "-" +
lastName.value;
}
else if(firstName.value.slice(0,1).match(/[A-Z]/)){
return firstName.value.slice(0,1)[0] + firstName.value.slice(1).toLowerCase() + "-" + lastName.value;
}
else{
return firstName.value + "-" + lastName.value;
}
}
)
</script>
<template>
<div>
<!--我们的v-model就是实现的页面中的数据和实际的进行的双向的绑定-->
<label for="firstName">姓:</label><input type="text" id="firstName" v-model="firstName"><br>
<label for="lastName">名:</label><input type="text" id="lastName" v-model="lastName"><br>
全名:<span>{{ fullName }}</span>
</div>
</template>
<style scoped>
</style>
使用计算属性的原因
通过实践我们是可以发现,如果说我们的使用的那个函数,那么每一次的修改都会出现一些缓存的数据
但是如果说我们使用的是那个计算属性,那么就可以实现基本的一些减少缓存的数量的效果
对上面的是否可读和是否可写来一个简述
1.可读可写就是实现了我们的那个get函数和set函数
get是用来获取数据的,set函数是用来设置页面的数据的
2.只可读的属性的话,那么只是写了我们的获取数据的部分,但是没有将我们的获取的数据进行返回给页面
vue3的监视
通过我们的那个监视数据的话,我们可以实现监视的数据含有:
ref定义的数据
reactive定义的数据
函数的一个返回值(getter函数)
包含上面的几种数据的数组
监视ref定义的基本数据
使用我们的watch的时候,我们的实现就是先导入watch
<script lang="ts" setup name="Person">
import {ref, watch} from "vue"
// 数据
let sum = ref(1);
// 方法
function SumPlusOne(){
sum.value += 1;
}
// 监视
// watch("监视的对象", 回调函数)
const StopWatch = watch(sum, (newValue, oldValue) =>{
// 我们的新的值和我们的那个页面中的值一直保持一致
console.log(newValue, oldValue);
// 我们在监视的时候,我们在某种的条件下面,还要进行解除监视
if(sum.value >= 10){
StopWatch();
}
});
</script>
<template>
<div>
<h2>{{ sum }}</h2>
<button @click="SumPlusOne">点击我sum+1</button>
</div>
</template>
<style scoped>
</style>
监视ref定义的对象类型
<script lang="ts" setup name="Person">
import {ref, watch} from "vue"
// 数据
let person = ref({
name:"张三",
age:20
})
// 方法
function AgePlusOne(){
person.value.age += 1;
}
// 监视
/*
* 第一个参数:监视的对象
* 第二个参数:监视的回调函数
* 第三个参数:监视的配置项
* */
const StopWatch = watch(person, (newValue, oldValue) => {
console.log(newValue, oldValue);
if(person.value.age > 30){
StopWatch()
}
},{
// 为了监视我们的ref定义的那个深层监视,所以我们要在这个里面实现基本的那个配置选项
deep: true, // 开始深层监视
immediate: true // 开启立即监视
})
</script>
<template>
<div>
<h2>{{ person.age }}</h2>
<button @click="AgePlusOne">修改人的年纪</button>
</div>
</template>
<style scoped>
</style>
监视reactive定义的数据
<script lang="ts" setup name="Person">
import {ref, watch, reactive} from "vue"
// 数据
let person = reactive({
name:"张三",
age:20
})
// 方法
function AgePlusOne(){
Object.assign(person, {age:25})
}
function changePerson(){
Object.assign(person, {name:"猪八戒",age:22})
}
// 开始实对reactive的监视
// reactive默认是开启的深度监视的
watch(person, (newValue, oldValue) => {
console.log(newValue, oldValue);
console.log("person变化了")
})
</script>
<template>
<div>
<h2>{{ person.age }}</h2>
<button @click="AgePlusOne">修改人的年纪</button>
<button @click="changePerson">改变每一个人</button>
</div>
</template>
<style scoped>
</style>
监视ref和reactive的数据
上面的数据的监视都是实现的对一组的数据进行的监视,没有实现对对象类型的数据中的某一个值进行监视成功
所以说,为了可以实现对对象中的某一个值进行监视,那么我们就要使用下面的方法来实现监视数据的基本变化
<script lang="ts" setup name="Person">
// 导入需要使用的
import {ref, reactive, watch} from "vue";
// 数据
let data = reactive({
name:"孙悟空",
age:12,
career:{
c1:"出租车死机",
c2:"程序员"
}
})
// 函数方法的开始
// 改变年纪
function changeDataAge(){
data.age = 19;
}
// 改变名称
function changeDataCareer(){
data.career = {
c1:"烧烤",
c2:"板砖"
}
}
// 改变名字
function chnageDataName(){
data.name = "猪八戒"
}
// 开始数据的监视
// 下面的是开始监视某一个数据的变化
// 监视age
watch(()=>data.age, (newVal) => {
console.log("年纪改变了",newVal)
})
// 监视name
watch(()=>data.name, (newVal) => {
console.log("年龄改变了",newVal)
})
// 监视career
watch(()=>data.career,(newVal) => {
console.log("事业改变了",newVal)
},{deep:true})
// 一般的话,我们的实现的就是使用函数时来进行监视我们的数据的变化
</script>
<template>
<!--开始结构的构建-->
<div>
<div>{{ data.name }}-{{data.age}}-{{data.career.c1}}-{{data.career.c2}}</div>
<button @click="changeDataAge">修改年纪</button>
<button @click="changeDataCareer">修改事业</button>
<button @click="chnageDataName">修改姓名</button>
</div>
</template>
<style scoped>
</style>
监视多个数据
首先来说,我们的最后的实现的效果就是同时监视多个数据的值的变化
<script lang="ts" setup name="Person">
// 导入需要使用的
import {ref, reactive, watch} from "vue";
// 数据
let data = reactive({
name:"孙悟空",
age:12,
career:{
c1:"出租车死机",
c2:"程序员"
}
})
// 函数方法的开始
// 改变年纪
function changeDataAge(){
data.age = 19;
}
// 改变名称
function changeDataCareer(){
data.career = {
c1:"烧烤",
c2:"板砖"
}
}
// 改变名字
function chnageDataName(){
data.name = "猪八戒"
}
// 开始数据的监视
// 下面的是开始监视某一个数据的变化
// 开始实现同时监视多个数据
watch(()=>[data.name, data.age, data.career],(newValue)=>{
console.log("data的数据有所改变了",newValue)
})
// 同时上面的那个还是可以实现那个另一个写法
watch([()=>data.name, ()=>data.age], (newValue)=>{
console.log("值变化了",newValue)
})
</script>
<template>
<!--开始结构的构建-->
<div>
<div>{{ data.name }}-{{data.age}}-{{data.career.c1}}-{{data.career.c2}}</div>
<button @click="changeDataAge">修改年纪</button>
<button @click="changeDataCareer">修改事业</button>
<button @click="chnageDataName">修改姓名</button>
</div>
</template>
<style scoped>
</style>
监视watchEffect的使用
<script lang="ts" setup name="Person">
// 导入需要使用的
import {ref, watch, watchEffect} from "vue";
// 数据
let data = ref(1)
let sum = ref(0)
// 方法
function changeData(){
data.value++
}
function changeSum(){
sum.value += 10;
}
// 监视数据变化
// 当我们的数据 data> 10的时候就停止监视
// 首先我们需要注意的是,我们的那个数据的话,newValue就是我们的新的值的变化,newValue === data
// 开始使用我们的watch来实现基本的那个数据的监视
let stopWatch = watch(()=>[data, sum], (newValue, oldValue)=>{
console.log("数据变化了", newValue, oldValue)
// 开始实现解构赋值
let [newData, newSum] = newValue;
if(newData.value >= 10 || newSum.value > 100) {
stopWatch()
}
},{deep:true})
/*
* watch和watchEffect的区别:
* 1.watch的功能的体现的话就是:需要我们的明确指出需要进行监视的数据,就有一定的惰性
* 2.watchEffect:我们的在使用的时候,不用告诉他我们需要进行监视的是哪一个,只要进行用就行了
*
* 下面的一个就是那个自动的监视,自动化的监视
* 注意监视的是哪个响应式数据的变化
* */
let stopWatch01 = watchEffect(()=>{
// 这个的话是默认的立即监视
if(data.value >= 10 || data.value > 100) {
stopWatch01()
}
})
</script>
<template>
<div>
<!--开始通过我们的插值语法来实现基本的数据展现-->
<span>{{ data }}</span><br>
<span>{{ sum }}</span><br>
<button @click="changeData">点击数字加1</button>
<br>
<button @click="changeSum">点击数字加10</button>
</div>
</template>
<style scoped>
</style>
vue3中的TS的使用
一般我们使用做项目的时候,我们使用的就是那个在types目录的下面使用我们的基本的类型的定义
这个基本的类型的使用就是使用的我们的那个typescript语言来实现的
TS的接口
export interface PersonInter {
id:string;
name: string;
age: number;
gender: string;
}
// 写好了,我们还要实现暴露
TS的自定义类型
export type PersonList = Array<PersonInter>
// 或者说,我们使用:export type PersonList = PersonInter[];
TS的泛型
// 泛型就是在 我们的那个后面添加一个那个:
type PersonInter;
vue中的使用
<script lang="ts" setup name="Person">
import {type PersonInter, type PersonList} from "@/types/index"
//开始使用我们的接口
// 使用接口来实现我们的限制一个人的数据格式
let person:PersonInter = {id:"xsddascddfvws", name:"寻悟空", age:500, gender:"男"};
// 开始定义一推人的规范
// 同时在下面中我们还可以使用: Array<PersonInter>
let personList:PersonList = [
{id:"cvsdcdfv01", name:"猪八戒", age:20, gender:"男"},
{id:"cvsdcdfv02", name:"白龙马", age:20, gender:"男"},
{id:"cvsdcdfv03", name:"唐三藏", age:20, gender:"男"}
]
</script>
<template>
</template>
<style scoped>
</style>
types/index.ts内容
// 定义接口,用于限制我们的那个Person的对象,并且把对象就行暴露
export interface PersonInter {
id:string;
name: string;
age: number;
gender: string;
}
// 开始定义一个那个自定义类型
export type PersonList = Array<PersonInter>
vue3中的props使用
首先的话,我们的这个部分就实现了基本的那个组进间的通讯
App.vue内容
<script lang="ts" setup name="App">
import person from "./components/Person.vue"
import {type PersonList} from '@/types'
import {reactive} from 'vue'
let personList = reactive<PersonList>([
{id:"cvsdcdfv01", name:"猪八戒", age:20, gender:"男"},
{id:"cvsdcdfv02", name:"白龙马", age:20, gender:"男"},
{id:"cvsdcdfv03", name:"唐三藏", age:20, gender:"男"}
])
</script>
<template>
<!--开始给我们的组件传递参数-->
<!--我们是可以通过v-bind来实现数据的绑定的,简写就是:属性名=属性值-->
<person :a="1+1" v-bind:personList="personList"/>
</template>
<style>
</style>
Components.vue内容
<script lang="ts" setup name="Person">
// 开始接收那个父组件给我们的传递的参数
import {defineProps, withDefaults} from "vue"
import {type PersonList, type PersonInter} from "@/types/index"
// 里面接收的是一个数组
// defineProps(["a", "personList"])
// 上面的只是实现的只接受数据,但是没有对只接受的数据进行一个限制
// 在数据的传输的时候,我们进行添加一个?,就可以实现基本的那个一个数据的接收与否
// 下面的那个实现的就是:personList?:PersonList,就是实现了我们的父组件中可以传入personList,也可以不传入
// defineProps<{personList?:PersonList, a:Number}>()
// 但是有的时候我们需要实现的就是:当我们的父组件没有传数据的时候,我们就要开始实现基本的那个指定默认值
// 所以说,我们的下面的语法就实现了我们的传递数据的时候的那个:
/*1.接收数据/ 2.限制接收的数据/ 3.数据是否必须接收/ 4.数据没有的收的默认值
* */
withDefaults(defineProps<{personList?:PersonList, a?:Number}>(),
{personList:()=>[{id:"", name:"", age:0, gender:""}], a:()=>10})
</script>
<template>
<h2>{{ a }}</h2>
<!--开始实现数据的渲染-->
<!--我们使用的是哪个v-for来实现数据的遍历和显示-->
<ul ><li v-for="i in personList" :key="i.id">{{ i.name }}-{{ i.age }}-{{ i.gender }}</li></ul>
</template>
<style scoped>
</style>
props的意义
首先我先声明一点,虽然是叫做那个props,但是写代码的时候,我们没有用到
我们的是新的效果就是实现组件通讯,就是把两个文件进行那个基本的绑定
vue3的生命周期
vue中的生命周期介绍
生命周期的其他的名称,生命周期函数,生命周期钩子
vue中的生命周期含有那个四个阶段
1.创建组件(创建前/创建后)
2.挂载组件(挂载前/挂载后)
3.更新组件(更新前/更新后)
4.销毁组件(销毁前/销毁后)
// 介绍我们的vue2的生命周期
1.beforeCreate / created
2.beforeMount / mounted
3.beforeUpdate / updated
4.beforeDestory / destoryed
我是可以通过debugger来实现基本的停止程序的运行的
销毁的实现就是通过那个v-if来实现的
vue2脚手架的启动项目的指令: npm run serve
// 开始vue3的生命周期
1.在我们的vue3中的创建是通过后面的那个setup函数来实现了统一的创建
2.onBeforeMount / onMounted 挂载
3.onBeforeUpdate / onUpdated 更新
4.onBeforeUnmount / onUnmounted 卸载
vue3的具体展现
App.vue
<script lang="ts" setup name="App">
import person from "./components/Person.vue"
import {ref} from "vue"
// 开始实现我们的那个组件的卸载
let show = ref(true);
function changeShow(){
if(show.value === true){
show.value = false
}else{
show.value = true
}
}
</script>
<template>
<!--开始渲染于页面-->
<button @mouseover="changeShow">当前的show的值为-{{ show }}</button>
<person v-if="show"/>
</template>
<style>
</style>
Index.vue
<script lang="ts" setup name="Person">
import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted} from 'vue'
// 数据
let sum = ref(0);
// 方法
function sumPlus(){
sum.value++;
}
// 开始生命周期钩子
// 创建部分
console.log("创建并且创建完毕");
// 挂载部分
onBeforeMount(()=>{
console.log("挂载前")
})
onMounted(()=>{
console.log("挂载完毕")
})
// 更新部分
onBeforeUpdate(()=>{
console.log("更新前")
})
onUpdated(()=>{
console.log("更新后")
})
// 卸载组件
onBeforeUnmount(()=>{
console.log("卸载前")
})
onUnmounted(()=>{
console.log("卸载后")
})
</script>
<template>
<div>
<h2>当前的求和为:{{ sum }}</h2>
<button @click="sumPlus">点击数字+1</button>
</div>
</template>
<style scoped>
</style>
注意我们的子组件和父组件的挂载的顺序就是:先挂载子组件,然后再挂载父组件
vue3的Hooks的使用
首先我们的这个部分,先实现的就是那个先下载我们的axios: npm install axios
hooks的实现就是将每一种的玩意归类,就是这个数据,以及这个数据进行的那个方法,都写在一起,这个就是hooks
原生的结构
<!--原生的代码-->
<script lang="ts" setup name="Person">
import {ref, reactive} from 'vue'
import axios from "axios"
// 数据
let sum = ref(0);
let images = reactive(["01.img"])
// 方法
function sumPlus(){
sum.value++;
}
async function getImg(){
try{
let result = await axios.get("https://dog.ceo/")
console.log(result.data)
} catch(error){
alert("500 服务器报错")
console.log(error)
images.push("02.img")
}
}
</script>
<template>
<div>
<h2>当前的求和为:{{ sum }}</h2>
<!--开始展现图片-->
<img v-for="(i, j) in images" :key="j" :src="i" alt="图片不存在"/>
<button @click="sumPlus">点击数字+1</button>
<button @click="getImg">点击发送请求</button>
</div>
</template>
<style scoped>
</style>
开始使用那个hooks来实现分类,首先先新建一个文件夹hooks
首先我们的那个hooks的使用也是含有那个规范的,就是处理那个数据的时候,命名就是那个use数据名
hooks/useSum
import {ref} from 'vue'
export default function(){
// 数据
const sum = ref<number>(0);
// 方法
function sumPlus(){
sum.value++;
}
// 然后向外面提供东西
return {sum, sumPlus}
}
hooks/useImages
import {reactive} from 'vue'
import axios from "axios"
export default function(){
// 数据
const images = reactive(["01.img"])
// 方法
async function getImg(){
try{
const result = await axios.get("https://dog.ceo/")
console.log(result.data)
} catch(error){
alert("500 服务器报错")
console.log(error)
images.push("02.img")
}
}
return {images, getImg}
}
Index.vue
<script lang="ts" setup name="Person">
import useSum from "@/hooks/useSum"
import useImages from "@/hooks/useImages"
// 开始调用我们的那两个函数
const {sum, sumPlus} = useSum();
const {images, getImg} = useImages();
</script>
<template>
<div>
<h2>当前的求和为:{{ sum }}</h2>
<!--开始展现图片-->
<img v-for="(i, j) in images" :key="j" :src="i" alt="图片不存在"/>
<button @click="sumPlus">点击数字+1</button>
<button @click="getImg">点击发送请求</button>
</div>
</template>
<style scoped>
</style>
我们实现hooks的基本的步骤:
就是先那个把原生的先给那个出来,然后实现基本的每一个数据和对应的方法的归类于一个hooks中的ts文件中
然后再进行改造,使用函数来实现包裹原本的那个属性和方法,最后还要把我们的那个函数暴露给外面进行使用
然后在函数中进行设置需要使用的返回值即可
注意这个里面有个坑,如果配置了那个eslint之后,我们就要使用我们的const来实现定义变量了
vue3的路由使用
vue3创建路由思路
首先我们需要先进行那个创建出以一个那个路由器router
然后就是在我们的那个路由器中进行那个配置我们的路由选即可route
使用路由的原因就是实现我们的单网页的开发
vue3的路由创建
1.首先需要注意我们的路由的导航区和展示区域
2.设置我们的路由器 npm i vue-router router目录
3.制定我们的路由规则(什么路径就对应我们的什么组件)
4.形成一个一个的.vue组件进行展现出来即可
router/index.ts
// 引入createRouter
import {createRouter, createWebHistory} from "vue-router"
// 开始引入一个一个的路由组件
// import {Home} from "@/components/Home.vue"
// import {Index} from "@/components/Index.vue"
// import {News} from '@/components/News.vue'
/*
* 首先我们在那个创建路由的时候,我们需要先考虑得到其中的路由模式
* */
// 创建一个路由器
const router = createRouter({
// 开始选择使用的路由模式
history: createWebHistory(),
// 配置每一个的路由选项
routes:[
{
path:"/Home",
component:()=>import('@/components/Home.vue'),
// conponent:Home
},
{
path:"/Index",
component:()=>import('@/components/Index.vue'),
// conponent:Index
},
{
path:"/News",
component:()=>import('@/components/News.vue'),
// conponent:News
}
]
})
// 开始暴露我们的那个路由器
export default router;
App.vue
<script lang="ts" setup name="App">
import person from "./components/Person.vue"
import {RouterView, RouterLink} from 'vue-router'
</script>
<template>
<person/>
<div>
<h2>vue路由</h2>
<!--导航区-->
<div>
<!--同时我们的那个含有的基本的结构就是那个含有一个属性来实现我们的一些其他的属性的设置-->
<!--active-class,就是设置我们的被激活时候的class,但是在这里我们就不进行设置-->
<router-link to="/Home">首页1</router-link>
<br>
<router-link to="/Index">首页2</router-link>
<br>
<router-link to="/News">首页3</router-link>
<br>
</div>
<!--展示区-->
<!--开始使用我们的路由展示的路由来实现展现-->
<router-view></router-view>
<div>
</div>
</div>
</template>
<style>
</style>
main.ts
import { createApp } from 'vue'
import App from './App.vue'
// 引入我们的路由器
import router from './router'
const app = createApp(App)
// 全局使用我们的路由器
app.use(router)
app.mount('#app')
首先为了我们开发的顺利,所以说,我们的基本的操作就是实现我们的那个路由的使用还有文件的基本的分类
1.router/index.ts 里面进行配置我们的路由的配置
2.main.ts中进行那个具体的路由的全局使用
3.App.vue中实现基本的那个router-link和router-view来实现占位,router-link中的有一个属性to来实现路由的跳转
active-class就是实现激活的时候的样式的设计
4.首先我们的在这里的展示不会这几基本的那个CSS样式的设计,只体现功能
注意点:我们的那个组件的话,实现的一些基本的方法的话,就是有一个路由的放置的位置,所以说,我们的不同功能的组件的存放的位置就会有所不同,比如说,我们的路由组件的存放位置是在views或者pages目录的下面,一般的常组件的话,我们的存放位置是那个components目录下的
然后对于我们的租价而言的话,我们的基本的实现的效果就是视觉上的消失,实际上销毁和挂载的实现,所以说一半的话,就要实现进行那个生命周期函数的书写
vue3区分路由组件和一般组件
首先我们如何实现区分路由组件还有那个一般组件
一般组件: 通过我们的亲手的书写标签来实现的
路由组件: 就是通过我们的那个路由的规则来实现的组件的使用
vue3的工作模式
路由的工作模式含两种,1.histroy模式, 2.hush模式
1.history模式——适用于前台项目
就是我们的在那个最后的项目上线的时候,我们需要使用就是那个实现基本的正确的url路径才可以实现最后的那个路由选择,路径不带那个#的
history:createWebHistory(), // 配置的方法
2.hush模式——适用于后台项目
兼容性好,但是路径url不太美观,路径是带有#的
history:createWebHushHistory() // 配置hush模式
vue3中的to两种写法
普通写法
<router-link to="/Home">首页1</router-link>
<br>
<router-link to="/Index">首页2</router-link>
<br>
<router-link to="/News">首页3</router-link>
<!--上面的就是我们的to的字符串的写法,同时也是最基本的写法格式-->
对象写法
<router-link :to="{path:'/Home'}">首页1</router-link>
<br>
<router-link :to="{path:'/Index'}">首页2</router-link>
<br>
<router-link :to="{path:'/News'}">首页3</router-link>
vue3的命名路由
无名路由
// 引入createRouter
import {createRouter, createWebHistory, createWebHushHistory} from "vue-router"
// 创建一个路由器
const router = createRouter({
// 开始选择使用的路由模式
history: createWebHistory(), // 这个是我们的history的路由模式
// history: createWebHushHistory(), // 这个是我们的那个hush模式的路由设置
// 配置每一个的路由选项
routes:[
{
path:"/Home",
component:()=>import('@/components/Home.vue'),
// conponent:Home
},
{
path:"/Index",
component:()=>import('@/components/Index.vue'),
// conponent:Index
},
{
path:"/News",
component:()=>import('@/components/News.vue'),
// conponent:News
}
]
})
// 开始暴露我们的那个路由器
export default router;
具名路由
实现具名路由的写法就是实现我们那个添加我们的后面的那个name属性
// 引入createRouter
import {createRouter, createWebHistory, createWebHushHistory} from "vue-router"
// 创建一个路由器
const router = createRouter({
// 开始选择使用的路由模式
history: createWebHistory(), // 这个是我们的history的路由模式
// history: createWebHushHistory(), // 这个是我们的那个hush模式的路由设置
// 配置每一个的路由选项
routes:[
{
path:"/Home",
name:"Home",
component:()=>import('@/components/Home.vue'),
// conponent:Home
},
{
path:"/Index",
name:"Index",
component:()=>import('@/components/Index.vue'),
// conponent:Index
},
{
path:"/News",
name:"News"
component:()=>import('@/components/News.vue'),
// conponent:News
}
]
})
// 开始暴露我们的那个路由器
export default router;
<!--所以i说我们通过上面的添加name属性后,我们就可以实现基本的那个通过name属性来识别路由-->
<router-link to="/Home">首页1</router-link>
<br>
<router-link :to="{path:'/Index'}">首页2</router-link>
<br>
<router-link :to="{name:'News'}">首页3</router-link>
vue3的嵌套路由
// 引入createRouter
import {createRouter, createWebHistory, createWebHushHistory} from "vue-router"
// 创建一个路由器
const router = createRouter({
// 开始选择使用的路由模式
history: createWebHistory(), // 这个是我们的history的路由模式
// history: createWebHushHistory(), // 这个是我们的那个hush模式的路由设置
// 配置每一个的路由选项
routes:[
{
path:"/Home",
name:"Home",
component:()=>import('@/components/Home.vue'),
// conponent:Home
// 开始添加那个子集路由,就是直接进行添加我们的那个chindren属性
children:[
{
// 注意我们的那个子集的路径里面是是不用书写/的
path:"detail",
name:"detail",
component:()=>import("子集路由的具体的路径")
}
]
},
{
path:"/Index",
name:"Index",
component:()=>import('@/components/Index.vue'),
// conponent:Index
},
{
path:"/News",
name:"News"
component:()=>import('@/components/News.vue'),
// conponent:News
}
]
})
// 开始暴露我们的那个路由器
export default router;
<!--开始设置我们那个基本的一些具体的一些路由的设计-->
<router-link to="/News/detail"></router-link>
<!--然后实现占位的路由的设计-->
<router-view></router-view>
vue3的路由传参
vue3路由的query参数
<!--父组件进行传递参数的时候的第一种写法-->
<router-link to="/News/detail?a=${news.a}&b=${news.b}&c=${news.c}"></router-link>
<!--父组件进行传递路由参数的第二种写法:to的对象写法-->
<router-link :to="{path:'/News/detail', query:{a:news.a, b:news.b, c:news.c}}"></router-link>
<!--开始实现接收参数-->
<script lang="ts" name="detail" setup>
// 开始传入模块方法
import {toRefs} from "vue";
import {useRoute} from "vue-router" // 这个就是一个hooks
const route = ussRoute();
// console.log(route)
// 我们通过后面的那个得到最后的那个route对象后,我们就可以得到父级路由进行返回的一个路由参数了
// 如果我们从一个响应式的对象中进行那个获取数据那个就会导致后面的那个失去响应式数据,这个时候就需要我们使用后面的那个toRefs
let {query} = torefs(route);
</script>
<template>
<!--开始实现我们那个基本的一些那个渲染数据-->
<div>{{ route.query.a }}</div>
<div>{{ route.query.b }}</div>
<div>{{ route.query.c }}</div>
<!--
<div>{{ query.a }}</div>
<div>{{ query.b }}</div>
<div>{{ query.c }}</div>
-->
</template>
同时我们为了我们的后面的那个就要实现基本的那个使用模板字符串来实现动态的传递数组 ${}
vue3路由的params参数
params参数的具体的使用就是使用我们的那个来实现基本的那个来实现基本的现在路由规则中进行占位
{
path:"/Home",
name:"Home",
component:()=>import('@/components/Home.vue'),
// conponent:Home
// 开始添加那个子集路由,就是直接进行添加我们的那个chindren属性
children:[
{
// 注意我们的那个子集的路径里面是是不用书写/的
path:"detail/:id/:name/:content?",
name:"detail",
component:()=>import("子集路由的具体的路径")
}
]
},
<!--第一种写法-->
<router-link to="/News/detail/${news.a}/${news.b}/${news.c}"></router-link>
<!--第二种写法-->
<router-link :to-{name:'detail', params:{a:news.a, b:news.b, c:news.c}}></router-link>
<!--开始实现接收参数-->
<script lang="ts" name="detail" setup>
// 开始传入模块方法
import {toRefs} from "vue";
import {useRoute} from "vue-router" // 这个就是一个hooks
const route = ussRoute();
// console.log(route)
// 我们通过后面的那个得到最后的那个route对象后,我们就可以得到父级路由进行返回的一个路由参数了
// 如果我们从一个响应式的对象中进行那个获取数据那个就会导致后面的那个失去响应式数据,这个时候就需要我们使用后面的那个toRefs
let {params} = torefs(route);
</script>
<template>
<!--开始实现我们那个基本的一些那个渲染数据-->
<div>{{ route.params.a }}</div>
<div>{{ route.params.b }}</div>
<div>{{ route.params.c }}</div>
<!--
<div>{{ params.a }}</div>
<div>{{ params.b }}</div>
<div>{{ params.c }}</div>
-->
</template>
pamars参数的实现的时候,我们的使用的首先现在那个路由的配置文件里面进行占位
然后再那个传参的时候使用的name来进行标识,不可以使用那个path来实标识
同时在那个路由器的配置的时候,我们的最后的实现的时候,可以使用我们的那个来实现一个参数占位的可选的值的设定 ?
vue3的路由props
我们使用那个props参数的时候,我们的那个具体的实现的是那个简化我们的传递参数
这个的使用,我们是可以使用那个路由的配置项 : props:true来实现的
结合我们的那个defineProps和pamars来使用的
{
path:"/Home",
name:"Home",
component:()=>import('@/components/Home.vue'),
// conponent:Home
// 开始添加那个子集路由,就是直接进行添加我们的那个chindren属性
children:[
{
// 注意我们的那个子集的路径里面是是不用书写/的
path:"detail/:id/:name/:content?",
// path:"detail"
name:"detail",
component:()=>import("子集路由的具体的路径"),
// 第一种写法:实现将路由收到的pamars参数来进行传递给路由组件
props:true
// 第二种写法的实现.就是通过的我们的函数来实现的
/*
这种的写法是结合我们的那个query参数来实现的
props(route){
return route.query;
}
*/
}
]
},
<router-link :to-{name:'detail', params:{a:news.a, b:news.b, c:news.c}}></router-link>
<!--开始实现接收参数-->
<script lang="ts" name="detail" setup>
defineProps(["a", "b", "c"])
</script>
<template>
<!--开始实现我们那个基本的一些那个渲染数据-->
<div>{{ a }}</div>
<div>{{ b }}</div>
<div>{{ c }}</div>
<!--
<div>{{ params.a }}</div>
<div>{{ params.b }}</div>
<div>{{ params.c }}</div>
-->
</template>
vue3的replace属性
<!--
首先我们的路由器的默认的配置的话,我们的实现的效果就是改变我们的浏览器的默认的那个可以前进和后退的属性设置
默认的是push,就是可以实现前进和后退
但是我们是可以实现改变这个的属性的:replace
首先的话,这个的使用就是实现的是那个: 再路由的导航区种添加这个
换言之就是进行设置我们的那个无痕浏览的模式
-->
<router-link replace to=""></router-link>
vue3的编程式路由导航
<template>
</template>
<script lang="ts" name="Component" setup>
import {onMounted} from "vue"
import {vueRouter} from "vue-router"
const router = vueRouter();
onMounted(){
setTimeout(()=>{
// push/replace中的参数的写法就是那个和to的写法式一致的
router.push("/Home");
}, 3000)
}
</script>
vue3的重定向问题
路由的重定向就是实现,就是使用了我们的那个:redirect
// 引入createRouter
import {createRouter, createWebHistory} from "vue-router"
// 创建一个路由器
const router = createRouter({
// 开始选择使用的路由模式
history: createWebHistory(),
// 配置每一个的路由选项
routes:[
{
path:"/Home",
component:()=>import('@/components/Home.vue'),
// conponent:Home
},
{
path:"/Index",
component:()=>import('@/components/Index.vue'),
// conponent:Index
},
{
path:"/News",
component:()=>import('@/components/News.vue'),
// conponent:News
},
// 开始我们的路由的重定向
{
path:"/",
redirect:"/Home"
}
]
})
// 开始暴露我们的那个路由器
export default router;
vue3的状态管理器
vue3的Pinia的使用
Pinia是一个vue.js的一符合直觉的状态管理库
Pinia就是一种集中式的状态管理,一般的话,是将我们的一些共享的数据(全局数据)交给我们的Pinia进行管理
git是一个分布式的数据状态管理
使用我们的这个状态管理器的话,我们使用的就是那个pinia: npm i pinia
开始改造我们的那个main.ts文件
import { createApp } from 'vue'
// 从我们的那个pinia中进行引入createPinia
import {createPinia} from 'pinia'
import App from './App.vue'
// 引入我们的路由器
import router from './router'
const app = createApp(App)
// 创建Pinia
const Pinia = createPinia()
// 全局使用我们的路由器
app.use(router);
// 全局使用pinia
app.use(Pinia);
app.mount('#app')
vue3使用Pinia
首先我们的下面的文件都是创建于我们的那个store文件夹中的,进行一个状态的管理,然后这个文件的下面的取名为count.ts
就是这个目录下面的文件的话,我们进行取名字的时候,一定要体现出来我们的那个基本的一些要做的事情
存储数据
// 通过文件名我们就可以知道。这个文件夹的下面,我们实现的就是那=那个和求和相关的内容
import {defineStore} from "pinia" // 使用这个来创建仓库
// 官方的推荐就是使用的名字的话,就是使用hooks的命名规范
export const useCountStore = defineStore("count",{
// state中就是我们用来真真存储数据的地方
state(){
return {
count: 0
}
}
})
读取数据
<script lang="ts" setup name="Person">
import {useCountStore} from "@/store/count"
import {ref} from "vue"
const countStore = useCountStore()
// console.log(countStore.count)
</script>
<template>
<div>{{ countStore.count }}</div>
</template>
<style scoped>
</style>
vue3的修改pinia数据
<script lang="js" setup name="Person">
import {useCountStore} from "@/store/count"
import {watch} from "vue"
const countStore = useCountStore()
// console.log(countStore.count)
function isEqul(){
console.log(countStore.count === countStore.$state.count)
}
// 开始实现数据的修改方法1
function changeData(){
countStore.count ++;
}
// 修改方法2
function addData(){
countStore.$patch = ({
count: 20
})
}
// 修改方式3
function add(n){
countStore.increment(n);
}
// 开始监视数据的变化
watch(()=>countStore.count,(newValue)=>{
console.log("数据变化了", newValue)
})
</script>
<template>
<div>{{ countStore.$state.count }}</div>
<button @click="isEqul">点击进行判断</button>
<button @click="changeData">点击修改数据1</button>
<button @click="addData">点击修改数据</button>
<button @click="add(78)">修改方法3</button>
</template>
<style scoped>
</style>
// 通过文件名我们就可以知道。这个文件夹的下面,我们实现的就是那=那个和求和相关的内容
import {defineStore} from "pinia" // 使用这个来创建仓库
// 官方的推荐就是使用的名字的话,就是使用hooks的命名规范
export const useCountStore = defineStore("count",{
// state中就是我们用来真真存储数据的地方
state(){
return {
count: 0
// 注意实际上,我们在这里可以实现返回多组数据
}
},
// actions中就是用于进行配置组件中对应的每一个动作
actions:{
increment(value:number){
this.count += value
console.log(this.count)
}
}
})
vue3中的storeToRefs和toRefs的区别
前者只是关注数据的变化,但是toRefs关注的是基本上所有的那个的变化
所以说一般的话,解构赋值,我们只关注那个数据的变化,那么我们使用的就是那个storeToRefs
这两个的作用都是为了方便我们从原本的一个响应式数据中解构赋值得出的值,来实现基本的那个防止其失去响应式数据的特点
但是注意的是,一个来自于我们的那个vue中的,一个来自于我们的那个pinia中的
vue3中的getters的使用
首先的话,这个也是我们的状态管理器中的一个配置选项
pinia 中的一个配置项
// 通过文件名我们就可以知道。这个文件夹的下面,我们实现的就是那个和求和相关的内容
import {defineStore} from "pinia" // 使用这个来创建仓库
// 官方的推荐就是使用的名字的话,就是使用hooks的命名规范
export const useCountStore = defineStore("count",{
// state中就是我们用来真真存储数据的地方
state(){
return {
count: 0
// 注意实际上,我们在这里可以实现返回多组数据
}
},
// actions中就是用于进行配置组件中对应的每一个动作
actions:{
increment(value:number){
this.count += value
console.log(this.count)
}
},
// 使用这个方法就是实现的我们的对数据不满意的时候,我们可以实习基本的那个一些方法来进行不改变原本的
// 设置的数据,来实现我们的返回新的值,代替原本设置的值
getters:{
// bigCount(){
// return this.count * 10
// },
bigCount:state => state.count * 10;
}
})
vue3的$subsscript使用
订阅,可以实现一定的代码的功能的实现,常用于那个序列化个反序列化的功能的实现
vu3的store的组合式写法
选项式写法
import {defineStore} from "pinia" // 使用这个来创建仓库
// 官方的推荐就是使用的名字的话,就是使用hooks的命名规范
export const useCountStore = defineStore("count",{
// state中就是我们用来真真存储数据的地方
state(){
return {
count: 0
// 注意实际上,我们在这里可以实现返回多组数据
}
},
// actions中就是用于进行配置组件中对应的每一个动作
actions:{
increment(value:number){
this.count += value
console.log(this.count)
}
},
getters:{
// bigCount(){
// return this.count * 10
// },
bigCount:state => state.count * 10;
}
})
组合式写法
import {ref} from "vue"
import {defineStore} from "pinia" // 使用这个来创建仓库
// 官方的推荐就是使用的名字的话,就是使用hooks的命名规范
export const useCountStore = defineStore("count",()=>{
// 函数相当于是那个actions
function increment(value:number){
this.count += value
console.log(this.count)
}
// 这个就是我们的那个响应式数据
const count = ref(0);
return {count, increment}
})
vue3的组件通信
组件通信1:props
Father.vue
<script setup lang="ts" name="Father">
import son from "@/components/Son.vue"
import {ref} from "vue"
// 父组件的数据
let car = ref("父亲汽车")
// 方法
function getToy(value:string){
console.log(value, "父亲给的");
}
</script>
<template>
<div>我是father组件</div>
<div>{{ car }}</div>
<!--开始实现我们的那个汽车的传递给我们的那个儿子-->
<son :car="car" :getToy="getToy"></son>
</template>
<style scoped>
</style>
Son.vue
<script setup lang="ts" name="Son">
import {ref} from "vue"
let player = ref("儿子玩具")
// 开始实现接收我们的那个还在传递过来的参数
defineProps(["car", "getToy"])
</script>
<template>
<div>我是儿子组件</div>
<div>{{ player }}</div>
<div>父亲传递的汽车是:{{ car }}</div>
<button @click="getToy(car)">打印</button>
</template>
<style scoped>
</style>
首先我们是可以通过我们的那个props来实现基本的那个数据的传输的,同时这个时候,我们是可以使用那个子传父,父传子
但是如果说实现那个子传父,那么我们需要进行的是那个基本的一些从父组件中进行传递一个函数过来使用
子组件中进行接收参数的时候,需使用的方法是defineProps
同时props也是使用频率最高的一个参数
但是那个props的适用场景是在我们的那个子父组件的通讯中的使用
组件通信2:自定义事件
自定义事件就是一个典型的将我们的子组件中的数据传递给那个父组件中
实现的步骤就是那个在我们的那个父亲中进行了那个绑定了一个自定义事件名,然后我们还要那个进行最后的那个在子组件中进行声明事件
自定义事件名的: @自定义事件名 = "需要进行的操作"
defineEmits同时在子组件中进行那个使用这个来接受自定事件
Father.vue
<script setup lang="ts" name="Father">
import son from "@/components/Son.vue"
import {ref} from "vue"
let str = ref("你好")
function test(value:Event){
str.value = "haha"
}
</script>
<template>
<div>我是father组件</div>
<div>{{ str }}</div>
<button @click="test">点击测试</button>
<button @click="str = '哈哈'">点击测试</button>
<!--<button @click="str = $event">点击</button> 这个就是一个事件对象-->
<son @haha="str = '哈哈'"></son>
</template>
<style scoped>
</style>
Son.vue
<script setup lang="ts" name="Son">
import {ref, onMounted} from "vue"
let str = ref("我是子组件")
const emit = defineEmits(["haha"])
onMounted(() => {
setTimeout(() => {
emit("haha");
// document.write(str.value)
}, 1000)
})
</script>
<template>
<button @click="emit('haha')">点击事件</button>
</template>
<style scoped>
</style>
组件通信3:_mitt
npm i mitt
首先的话,这个的话,工程化开发的时候,处于的文件夹的下面的是那个: tools或者 utils的目录下面
tools/emitter或者utils/emitter
// 首先先引入模块
import mitt from "mitt"
// export default mitt();
/*
* 或者使用:
* // 调用mitt得到emitter
* const emitter = mitt();
* // 暴露emitter
* export default emitter;
* */
// 调用mitt得到emitter
const emitter = mitt();
// 开始绑定事件
emitter.on("test", () => {
console.log("emitter ready")
})
// 开始触发事件
setTimeout(() => emitter.emit("test"), 2000)
// 开始实现1s后解绑test
setTimeout(() => emitter.off("test"), 2000)
setTimeout(() => emitter.all.clear(), 2000)
// 暴露emitter
export default emitter;
main.ts
import { createApp } from 'vue'
// 从我们的那个pinia中进行引入createPinia
import {createPinia} from 'pinia'
import App from './App.vue'
// 引入我们的路由器
import router from './router'
// 引入mitt
import emitter from '@/tools/emitter'
const app = createApp(App)
// 创建Pinia
const Pinia = createPinia()
// 全局使用我们的路由器
app.use(router);
// 全局使用pinia
app.use(Pinia);
app.mount('#app')
组件通信4:v-model
这个的话,常用于我们的那个进行数据和页面的交互的一个玩意
常用于进行构建ui组件库,构建ui组件库就是使用了我们的那个v-model的底层原理
首先ui组件库的使用的时候,使用我们的那个: defineProps和defineEmits
组件通信5:$attrs
就是可以实现我们的那个跨级的传递数据
就是在我们的那个中间的一个连接组件中直接实现基本的那个: v-bind="$attrs"
就可以实现孙子从爷爷那里找属性来呈现
v-bind="{x:100, y:200}" ==== :x="100" :y="200";
组件通信6:parent
$refs是一个典型的父传子
$parent是一个典型的子传父
组件通信7:provide和Inject
主要适用于进行那个爷爷和孙子之间进行那个传递参数的
vue3的插槽
vue3的默认插槽
实现的时候,首先将我们的那个组件标签写成那个双标签的形式
<Component>
<span>你好</span>
</Component>
但是在这个时候,我们的子组件中的不知道那个span在什么地方进行排放,所以说,就要在我们的slot写在子组件中的需要进行排放的位置
<slot>默认内容</slot>
<!--这个的作用和我们的那个router-view是一样的用法,只用书写一个就行了-->
首先我们的默认插槽只具有一个占位
vue3的具名插槽
使用具名插槽就是为了实现我们基本的那个将我们的内容实现放在不同的位置,
对于那个父组件而言,就是使用我们的那个v-slot===#来实现那个取名
在子组件中就是使用我们的那个:name属性来实现
<Component v-slot:s1>
<span>你好</span>
</Component>
<!--=======================================-->
<slot name="s1">默认内容</slot>
vue3的作用域插槽
自行了解
vue3的shallowRef和shallowReactive
这两个就是实现对浅层次的ref以及reactive才具有那个响应式数据的特点要求
对于我们的那个.value就是那个第一层
使用这个就是为了实现我们的基本的那个提高效能
vue3的readonly和showReadonly
就是只读属性,然后只有我们那个实现基本的一些那个才可以实现基本的修改
这个是通过一个响应式数据来实现的那个复制一个那个只读的一个数据出来
vue3中的那个toRow和 markRow
toRow就可以实现将我们的那个一个数据改变为原本的对象
mockjs的使用,就是可以实现当我们的后端还没有那个提供接口的时候,直接弄出来接口即可:npm i mockjs
import mockjs from "mockjs"
这个时候,我们的那个mockjs才需要使用那个markRow来实现标志,一旦标记,那么就一致保持那个最初的状态
vue3的customRef的使用
自定义customRef
vue3的全局API的实现
app.component 实现注册全局组件
app.config 就是那个全局的配置,就可以实现定义那个全局的变量
app.directive 用于进行注册全局指令的