Vue3的创建
npm create vite@latest
1.设置项目名。
2.选择框架。
3.选择支持的语法,默认使用TS。
......
Vue3的使用
setUp(无法直接修改数据,也就是没有响应式)
在vue3中不不再推荐使用选项式编程而是使用组合式编程。
Vue2写法
<template>
<div>
<span>姓名:{{name}}</span>
<br>
<span>年龄:{{age}}</span>
<br>
<button @click="setName()">修改名字</button>
<button @click="addAge()">年龄+1</button>
</div>
</template>
<script lang="ts">
export default {
name: 'Person',
data() {
return {
name: 'tolen',
age: 18
}
},
methods: {
setName() {
this.name = 'ostkaka'
},
addAge() {
this.age++;
}
},
}
</script>
Vue3写法
<template>
<div>
<span>姓名:{{name}}</span>
<br>
<span>年龄:{{age}}</span>
<br>
<button @click="setName()">修改名字</button>
<button @click="addAge()">年龄+1</button>
</div>
</template>
<script lang="ts">
export default {
name: 'Person',
setup() {
//变量
let name = 'tolen';
let age = 18;
//函数
function setName() {
name = 'ostkaka'
}
function addAge() {
age++;
}
return {name, age, setName, addAge}
}
}
</script>
如果data函数和setup中设置的变量名相互冲突的时候会优先读取setup中的数据。
但是每次都需要return对应的数据,写起来非常的麻烦,所以我们可以将setup单独写一个script。
<template>
<div>
<span>姓名:{{name}}</span>
<br>
<span>年龄:{{age}}</span>
<br>
<button @click="setName()">修改名字</button>
<button @click="addAge()">年龄+1</button>
</div>
</template>
<!-- 如果没有主键名字的要求,我们甚至可以将此script省略掉 -->
<script lang="ts">
export default {
name: 'Person',
}
</script>
<script lang="ts" setup>
//变量
let name = 'tolen';
let age = 18;
//函数
function setName() {
name = 'ostkaka'
}
function addAge() {
age++;
}
</script>
ref(用于定义响应式的基本数据,也可以定义对象,但是无法保证嵌套响应)
在我们需要保证响应式的数据赋值上使用ref函数,并且操作其中的vlaue属性,主要就是对value进行操作。
<script lang="ts" setup>
import { ref } from 'vue'
//变量,使用ref函数包裹
let name = ref('tolen');
let age = ref(18);
//函数,主要做到响应式的效果就是使用ref中的value属性
function setName() {
name.value = 'ostkaka'
}
function addAge() {
age.value++;
}
</script>
reactive(用于定义响应式的对象)
在我们需要保证对象嵌套式的相应的时候我们就可以使用reactive。
<template>
<div>
<span>车牌:{{car.name}}</span>
<br>
<span>价格:{{car.cost}}</span>
<br>
<button @click="setName()">修改名字</button>
<button @click="addAge()">加价</button>
</div>
</template>
<!-- 如果没有主键名字的要求,我们甚至可以将此script省略掉 -->
<script lang="ts">
export default {
name: 'car',
}
</script>
<script lang="ts" setup>
import {reactive } from 'vue'
//对象
let car = reactive({
name:'BYD',
cost: 2000000
});
//函数
function setName() {
car.name = 'ostkaka'
}
function addAge() {
car.cost+=10000;
}
</script>
当要使用响应式对象赋值的时候,我们需要使用toRefs函数来将对象中键值赋值为响应式的数据。
我们每次使用ref中数据的时候都需要添加 .value,写起来非常的麻烦,所以我们可以配置插件进行修改。
computed
编写计算属性,且计算属性是只读的,不同于普通的属性。
<template>
<div>
性:<input v-model="firstName"/>
<br>
名:<input v-model="secondName"/>
<br>
名字:<span>{{name}}</span>
<button @click="change()">修改名字</button>
</div>
</template>
<!-- 如果没有主键名字的要求,我们甚至可以将此script省略掉 -->
<script lang="ts">
export default {
name: 'car',
}
</script>
<script lang="ts" setup>
import {ref, computed} from 'vue'
let firstName=ref("to");
let secondName=ref("len");
let name = computed({
set(val) {
const[str1, str2] = val.split('-');
firstName.value = str1;
secondName.value = str2;
},
get() {
return firstName.value + secondName.value;
}
});
let change = function() {
name.value = "ost-kaka";
}
</script>
在Vue3中主要就是引入computed函数,通这个函数来创建属性,并且在该函数中主要就是编写 set(修改属性)和get(获取属性)函数。
watch
watch是一个监听函数,我们且有三个参数:数据源,回调函数,监听配置。
watch的数据源只能是: ref,reactive,对象,gatter函数(返回一个数据)。
例子
<template>
<div>
名字:<span>{{name}}</span>
<br>
年龄:<span>{{age}}</span>
<br>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
</div>
</template>
<!-- 如果没有主键名字的要求,我们甚至可以将此script省略掉 -->
<script lang="ts">
export default {
name: 'car',
}
</script>
<script lang="ts" setup>
import {ref, watch} from 'vue'
let name = ref("tolen");
let age = ref(18);
let changeName = function() {
name.value +='~';
}
let changeAge = function() {
age.value++;
}
watch(name, function() {
if(name.value != "ostkaka") {
console.log(name.value);
}
})
</script>
暂停监听
//返回值就是暂停函数,通过对应的条件调用暂停函数
let stop = watch(() => person.value.name, function() {
//编写对应的回调函数
if(1==1) {
stop();
}
})
特殊情况
1.数据源是ref的话,直接使用ref就可以,不需要添加.value。
2.数据源是ref定义的对象的话,其默认是不支持深度监听的,所以需要在watch配置中添加deep:true。
watch(name, function() {
if(name.value != "ostkaka") {
console.log(name.value);
}
},{deep:true})
3.数据源是reactive定义的话,其是默认开启深度监听的。
4.监听ref或reactive定义的对象中某个属性的时,如果属性是基本类型的话使用getter函数,如果是对象类型的话,可以直接监听,但是还是推荐使用getter函数,是可以在做对象属性监听的时候都使用getter函数进行编写。
//person.value.name对应ref中对象的属性
watch(() => person.value.name, function() {
//编写对应的回调函数
})
5.如果需要监听多个数据源的话,直接使用数组进行收集。
当我们需要自动去监听某些数据源的时候,我们就可以使用watchEffect,而watch需要我们手动的指出需要监听的数据源。
<template>
<div>
名字:<span>{{name}}</span>
<br>
年龄:<span>{{age}}</span>
<br>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
</div>
</template>
<!-- 如果没有主键名字的要求,我们甚至可以将此script省略掉 -->
<script lang="ts">
export default {
name: 'car',
}
</script>
<script lang="ts" setup>
import {ref, watchEffect} from 'vue'
let name = ref("tolen");
let age = ref(18);
let changeName = function() {
name.value +='~';
}
let changeAge = function() {
age.value++;
}
watchEffect(function() {
console.log(name.value)
})
</script>
标签中的ref属性
如果使用标签中的id作为唯一标识的话,在不同的组件之间就会有冲突的风险。使用使用ref作为容器用于间隔。
<template>
<div>
名字:<span ref="person">{{name}}</span>
</div>
</template>
<script lang="ts">
export default {
name: 'car',
}
</script>
<script lang="ts" setup>
//且person中的值就是该标签的数据。
let person = ref();
</script>
如果ref加在html标签上,则其数据就是标签数据,如果ref加在主键标签上,则其数据就是主键数据。
ts类型规范
自定义接口
//对应的自定义类型
export interface Person {
name: string,
age: number,
}
//标识对应类型的数组形式
export type Persons = Array<Person>
在vue中进行使用
<script lang="ts" setup>
import {Persons, type Person} from '../types/index'
let ren:Person = {name:'tolen', age: 18};
let rens:Persons = [
{name:'tolen', age: 18},
{name:'tolen', age: 18},
{name:'tolen', age: 18}
];
</script>
props
使用defineProps函数进行参数的传递。
//父组件传入对应的list集合
<template>
<div>
<ul>
<li v-for="item in list" :key="item.age">
{{item.name}} -- {{item.age}}
</li>
</ul>
</div>
</template>
<!-- 如果没有主键名字的要求,我们甚至可以将此script省略掉 -->
<script lang="ts">
export default {
name: 'car',
}
</script>
<script lang="ts" setup>
import {defineProps} from 'vue';
defineProps(['list']);
</script>
将接口写入泛型就可以指定对应类型的数据。
<script lang="ts" setup>
import {Persons } from '../types';
import {defineProps} from 'vue';
defineProps<{list?:Persons}>();
</script>
使用withDefaults,设置默认的数据。且需要是个函数返回对应的数据。
<script lang="ts" setup>
import {Persons } from '../types';
import {defineProps, withDefaults} from 'vue';
// defineProps<{list?:Persons}>();
withDefaults(defineProps<{list?:Persons}>(), {
list: () => [{name: 'ostkaka', age: 45}]
});
</script>
Vue的生命周期
1.创建:setUp中的代码就是创建时需要执行的代码。
2.挂载前/挂载:使用onBeforeMount和onMounted。
//挂载前
onBeforeMount(() => console.log("挂载前"));
//完成挂载
onMounted(() => console.log("完成挂载"));
3.更新前/更新:使用onBeforeUpdated和onUpdated。
//更新前
onBeforeUpdate(() => console.log("更新前"));
//更新完成
onUpdated(() => console.log("更新"));
4.卸载前/卸载:使用onBeforeUnmount和onUnmounted
//卸载前
onBeforeUnmount(() => console.log("卸载前"));
//卸载完成
onUnmounted(() => console.log("卸载完成"));
hooks
将相同模块的代码放在同个ts文件中,进行统一的维护。
集中的ts文件
import { ref } from "vue";
export default function() {
let num = ref(50);
let add = function() {
return num.value += 10;
}
//返回数据可以存在多个
return {num, add};
}
在主键中使用
<script lang="ts" setup>
import useradd from '../hooks/useAdd'
const {num,add} = useradd();
</script>
路由
安装路由
npm i vue-router
创建router文件/index.ts,创建路由规则。(使用history的工作模式,也可以使用哈希模式(就是路径中带#))
import {createRouter, createWebHistory} from "vue-router";
import blog from '../page/blog.vue'
import user from '../page/user.vue'
const router = createRouter({
//使用history的工作模式,也可以使用哈希模式(就是路径中带#)
history: createWebHistory(),
routes:[
{ name: 'blog'
path:'/blog',
component: blog
},
{
name: 'user',
path:'/user',
component: user
}
]
})
export default router
在main.ts中使用router。
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
let app = createApp(App);
app.use(router);
app.mount('#app');
使用router-link标签进行跳转(可以使用字符串,也可以使用 对象形式,对象中可以使用name和path来指定路由),使用router-view指定渲染vue主键的位置。
App.vue例子
<script setup lang="ts">
</script>
<template>
<router-link to="/blog">博客区</router-link> <span>||</span>
<router-link to="/user">用户区</router-link>
<hr>
<router-view></router-view>
</template>
测试结果
如果在子页面中还要展示其他的小页面的话,就可以使用子路由,使用参数 children。
路由传递参数
在router-Link中的to属性可以传入query/params参数。
<router-link :to="
{
name: 'blog',
query/params: {
name: 'ostkaka',
age: 13
}
}
">博客区</router-link>
在对应的组件上使用useRoute函数进行接收。
import {useRoute} from 'vue-router'
let route = useRoute();
// route.query / route.param
可以使用restful风格,在路由配置中编写路径格式,必须使用name进行配置。(如果某个参数非一定存在的话就在其后加`?`)
在对应的组件上使用useRoute.params进行接收。
编程式路由导航
使用route-Link是在template中进行编写的,如果需要在script中编写的话,我们需要使用useRouter进行编写。useRouter.push函数跳转到对应的路径。(运用场景:定时跳转,划过跳转,等等,在script编程)
重定向
将一个路径直接重定向到另一个路径上。
pinia
作用:集中管理数据。
安装
npm i pania
在main.t中引入并使用pinia。
import { createApp } from 'vue'
import App from './App.vue'
import {createPinia} from 'pinia'
let app = createApp(App);
//创建pinia
const pinia = createPinia();
//使用pinia
app.use(pinia);
app.mount('#app');
存储数据:创建文件夹 /store,并创建对应模块的文件,在state中编写对应的数据。
import {defineStore} from 'pinia'
export const useAddStore = defineStore('add', {
state() {
return {
sum: 1,
size: 1
}
}
})
修改数据
1.直接修改。
<script setup lang="ts">
import {useAddStore} from '../store/add'
let addStore = useAddStore();
console.log(addStore);
let add = function () {
addStore.sum += addStore.size;
}
let minus = function () {
addStore.sum -= addStore.size;
}
</script>
2.使用$patch函数。
<script setup lang="ts">
import {useAddStore} from '../store/add'
let addStore = useAddStore();
//修改对应对应的属性
addStore.$patch({
sum: 100,
size: 2
})
</script>
3.通过action属性进行修改。
import {defineStore} from 'pinia'
export const useAddStore = defineStore('add', {
actions: {
add(sum, size) {
this.sum = sum;
this.size = size;
}
},
state() {
return {
sum: 1,
size: 1
}
}
})
在对应的组件中直接调用此函数即可修改。
storeToRefs的使用
如果需要使用store中的数据时为了不破坏响应式,我们就可以使用storeToRefs来保证数据的响应式。(storeToRefs('store'))
组件通信
1.使用自定义事件(子传父常使用)
在传递者进行 定义事件和触发事件
<script setup lang="ts">
import{onMounted} from 'vue'
//声明事件
const emit = defineEmits(['send-toy']);
onMounted(() => {
emit('send-toy', 'ostkaka');
})
</script>
获得数据者进行 事件的绑定
<script setup lang="ts">
import Add from './components/Add.vue'
import Love from './components/Love.vue'
let saveToy = function(value:any) {
console.log('@', value);
}
</script>
<template>
<Add @send-toy="saveToy"/>
<hr>
<Love/>
</template>
2.使用mitt组件(任意主件间通信)
下载mitt
npm i mitt
创建mitt工具包
//引入mitt
import mitt from 'mitt'
const emitter = mitt()
export default emitter
在需要进行通信的组件中进行引入
在获取数据的组件中使用emitter.on进行事件的绑定
<script setup lang="ts">
import emitter from './utils/emitter'
//绑定事件
emitter.on('send-toy', (value:any) => {
console.log("@", value)
})
</script>
在传递数据的组件中使用emitter.emit进行事件的触发
<script setup lang="ts">
import emitter from '../utils/emitter'
// 触发事件
emitter.emit('send-toy', 'ostkaka')
</script>
3.使用provide和inject实现爷孙数据传递
在上级处使用provide函数来传递数据给子级。
<script setup lang="ts">
import { provide, ref } from 'vue'
let money = ref(100);
//向自己的子孙通过数据
provide('money', money);
</script>
在子级处使用inject函数来接收上级的数据。
<script setup lang="ts">
import { inject } from 'vue';
//使用上级的数据,第二个参数为默认数据
let money = inject('money', 1);
</script>
最终实现上级向子级数据的传递。
插槽
1.默认插槽
在对应的组件中编写插槽位置。
<template>
<slot></slot>
</template>
<script lang="ts">
export default {
name: 'Add'
}
</script>
<script setup lang="ts">
</script>
在调用处使用。
<template>
<Add>
<span>你好</span>
</Add>
</template>
2.具名插槽
指定标签存放在对应的插槽上。
<template>
<slot name="s1"></slot>
<slot name="s2"></slot>
</template>
<script lang="ts">
export default {
name: 'Add'
}
</script>
<script setup lang="ts">
</script>
使用标签填充插槽。
<template>
<Add>
<template v-slot:s1>
<span>你好</span>
</template>
<template #s2>
<span>ostkaka</span>
</template>
</Add>
</template>
可以使用 # 代替 v-slot: 指定插槽。
3.作用域插槽
当插槽的组件的数据需要传递到调用者时就可以使用此插槽。
<template>
<slot name="s1" :userName="name"></slot>
</template>
<script lang="ts">
export default {
name: 'Add'
}
</script>
<script setup lang="ts">
import { ref } from 'vue';
let name = ref('ostkaka');
</script>
调用者使用传来的数据。
<script setup lang="ts">
import Add from './components/Add.vue'
</script>
<template>
<Add>
<template v-slot:s1="value">
<span>你好</span>
<span>{{value.userName}}</span>
</template>
</Add>
</template>