Vue3基础
1、简介
相比Vue2
- 性能提升:打包大小减少、渲染更快、内存减少
- 源码升级:使用proxy代替defineProperty实现响应式、重写虚拟DOM的实现和Tree-Shaking
- 更好支持TypeScript
- 新特性:组合API、新内置组件…
2、安装
安装nodejs,下载地址:https://nodejs.org/en/download/
在命令行界面运行,参考网址:https://cn.vuejs.org/guide/quick-start.html
npm create vue@latest
3、简单上手
入口文件index.html
extensions.json推荐安装插件
src中的文件
main.ts
import './assets/main.css'
import { createApp } from 'vue'//引用创建应用
import App from './App.vue'//引入组件
createApp(App).mount('#app')//关联组件与应用并挂载到容器中
App.vue
<template>
<!-- html 结构 -->
</template>
<script>
<!-- js、ts 交互 -->
</script>
<style>
/* 样式 */
</style>
编写App.vue
<template>
<div class="app">
<h1>
hello
</h1>
</div>
</template>
<script lang="ts">
export default{
name:'App'//组件名
}
</script>
<style>
.app{
background-color: brown;
box-shadow: inset;
border-radius: 10px;
padding: 20px;
}
</style>
4、核心语法(组合式API)
1、setup
setup是vue3的一个新的配置项,值是一个函数,组件中所用的数据、方法、计算属性、监视等都配置在setup中,setup的生命周期在beforeCreate()之前,vue2语法可以和vue3语法共存,但vue3不能调vue2的东西,但vue2能调vue3的东西
<template>
<!-- html 结构 -->
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="showTel">查看电话</button>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
</div>
</template>
<script lang="ts">
import { setgroups } from 'process'
export default{
name:'Person',//组件名
setup() {//setup中的this是undefined,所以不能用this
//数据,这种数据为非响应式,不能自动更新
let name='zhangsan'
let age=18
let tel='18888888889'
//方法
function showTel(){
alert(tel)
}
function changeName(){
name='lisi2'
console.log(222223)
}
function changeAge(){
age=22
}
return {name,age,tel,showTel,changeName,changeAge}
},
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
setup返回值可以是渲染函数(了解)
2、简化setup写法
不使用插件有两个script标签
<template>
<!-- html 结构 -->
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="showTel">查看电话</button>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
</div>
</template>
<script lang="ts">
export default{
name:'Person'//组件名
// setup() {//setup中的this是undefined,所以不能用this
// //数据,这种数据为非响应式,不能自动更新
// let name='zhangsan'
// let age=18
// let tel='18888888889'
// //方法
// function showTel(){
// alert(tel)
// }
// function changeName(){
// name='lisi2'
// console.log(222223)
// }
// function changeAge(){
// age=22
// }
// return {name,age,tel,showTel,changeName,changeAge}
// },
}
</script>
<script setup lang="ts">//相当于setup函数
let name='zhangsan'
let age=18
let tel='18888888889'
//方法
function showTel(){
alert(tel)
}
function changeName(){
name='lisi2'
console.log(222223)
}
function changeAge(){
age=22
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
使用插件简化成一个标签
安装插件
npm i vite-plugin-vue-setup-extend -D
修改vite.config.ts
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
VueSetupExtend()
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
修改vue
<template>
<!-- html 结构 -->
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="showTel">查看电话</button>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
</div>
</template>
<script setup lang="ts" name="Person111">//相当于setup函数
let name='zhangsan'
let age=18
let tel='18888888889'
//方法
function showTel(){
alert(tel)
}
function changeName(){
name='lisi2'
console.log(222223)
}
function changeAge(){
age=22
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
3、响应式数据
ref->基本数据类型、对象数据类型 reactive->对象数据类型
引入ref将数据对象化,响应式数据背后是RefImpl实现类,故在使用函数更改数据时,需要对对象的value字段进行更改。
<template>
<!-- html 结构 -->
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="showTel">查看电话</button>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
</div>
</template>
<script setup lang="ts" name="Person111">//相当于setup函数
import {ref} from 'vue'
//只有要变化的才加ref变成响应式
let name=ref('zhangsan')
let age=ref(18)
let tel='18888888889'
//方法
function showTel(){
alert(tel)
}
function changeName(){
name.value='lisi2'
console.log(222223)
}
function changeAge(){
age.value=22
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
使用reactive使对象变成响应式
<template>
<!-- html 结构 -->
<div class="car">
<h2>一辆{{car.brand}}车,价值{{car.price}}万</h2>
<button @click="changePrice">修改汽车价格</button>
<br>
<h2>游戏</h2>
<ul>
<li v-for="g in games" :key="g.id">{{g.name}}</li>
</ul>
<button @click="changeGame">修改游戏名</button>
</div>
</template>
<script setup lang="ts" name="car">//相当于setup函数
import {reactive} from 'vue'
let car=reactive({brand:'BMW',price:100})
let games=reactive([
{id:1,name:'wangzhe1'},
{id:2,name:'wangzhe2'},
{id:3,name:'wangzhe3'},
])
function changeGame(){
games[0].name='2222'
}
function changePrice(){
car.price+=10
}
</script>
<style scoped>
button{
margin: 0 5px;
}
</style>
使用ref使对象变成响应式
<template>
<!-- html 结构 -->
<div class="car">
<h2>一辆{{car.brand}}车,价值{{car.price}}万</h2>
<button @click="changePrice">修改汽车价格</button>
<br>
<h2>游戏</h2>
<ul>
<li v-for="g in games" :key="g.id">{{g.name}}</li>
</ul>
<button @click="changeGame">修改游戏名</button>
</div>
</template>
<script setup lang="ts" name="car">//相当于setup函数
import {reactive} from 'vue'
import {ref} from 'vue'
let car=ref({brand:'BMW',price:100})
let games=reactive([
{id:1,name:'wangzhe1'},
{id:2,name:'wangzhe2'},
{id:3,name:'wangzhe3'},
])
function changeGame(){
games[0].name='2222'
console.log(games)
}
function changePrice(){
car.value.price+=10
console.log(car)
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
ref响应式对象RefImpl包含了reactivate响应式对象Proxy(Object),ref的value字段就是Proxy(Object),如图:
使用ref每次都要.value,可使用插件volar进行提示,插件设置里打钩。
reactive局限性:经过reactive形成的对象,在给对象赋值时,该对象失去响应式。ref就不会!
<template>
<!-- html 结构 -->
<div class="car">
<h2>一辆{{car.brand}}车,价值{{car.price}}万</h2>
<button @click="changePrice">修改汽车价格</button>
<button @click="changeCar" >修改汽车对象</button>
<br>
</div>
</template>
<script setup lang="ts" name="car">//相当于setup函数
import {reactive} from 'vue'
import {ref} from 'vue'
let car=reactive({brand:'BMW',price:100})
function changeCar(){
// car={brand:'benchi',price:200} 这么重新赋值对象,对象失去响应式,无法更新数据
// car=reactive({brand:'benchi',price:200}) 这么重新赋值对象,对象失去响应式,无法更新数据
Object.assign(car,{brand:'benchi',price:200})
}
function changePrice(){
car.price+=10
console.log(car)
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
ref、reactivate使用原则:
- 基本类型数据响应式:ref
- 对象响应式、层级不深:ref、reactive
- 对象响应式、层级深:reactive
4、toRefs与toRef
toRefs与toRef都是把一个响应式对象里的东西解构拿出来,并依然具备响应式能力
<template>
<!-- html 结构 -->
<div class="car">
<h2>一辆{{car.brand}}车,价值{{price}}万</h2>
<button @click="changePrice">修改汽车价格</button>
<button @click="changeCar" >修改汽车对象</button>
<br>
</div>
</template>
<script setup lang="ts" name="car">//相当于setup函数
import {reactive,ref,toRefs} from 'vue'
let car=ref({brand:'BMW',price:100})
let {brand,price}=toRefs(car.value)
let n=toRef(car.value,'price')
console.log(n)
function changeCar(){
//car.value={brand:'benchi',price:200} //这么重新赋值对象,对象失去响应式,无法更新数据
// car=reactive({brand:'benchi',price:200}) 这么重新赋值对象,对象失去响应式,无法更新数据
// Object.assign(car,{brand:'benchi',price:200})
}
function changePrice(){
price.value+=10
}
</script>
<style scoped>
button{
margin: 0 5px;
}
</style>
5、computed计算属性
computed有缓存,一般只计算一遍,function没有缓存。计算属性直接写名就能用,方法必须要调用才行。
<template>
<!-- html 结构 -->
<div class="person">
姓<input type="text" v-model="firstName">
<br>
名<input type="text" v-model="lastName">
<br>
全名<span>{{fullName}}</span>
</div>
</template>
<script setup lang="ts" name="Person111">//相当于setup函数
import {computed, ref} from 'vue'
let firstName=ref('zhang')
let lastName=ref('san')
let fullName=computed(()=>{
return firstName.value.slice(0,1).toUpperCase()+firstName.value.slice(1)+lastName.value//姓的首字母大写
})
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
但上述computed是只读的。如要修改计算属性,在计算属性中增加get、set函数来修改计算属性
<template>
<!-- html 结构 -->
<div class="person">
姓<input type="text" v-model="firstName">
<br>
名<input type="text" v-model="lastName">
<br>
全名<span>{{fullName}}</span>
<button @click="changeFullName">全名改成li-si</button>
</div>
</template>
<script setup lang="ts" name="Person111">//相当于setup函数
import {computed, ref} from 'vue'
let firstName=ref('zhang')
let lastName=ref('san')
let fullName=computed({
get(){
return firstName.value.slice(0,1).toUpperCase()+firstName.value.slice(1)+'-'+lastName.value//姓的首字母大写
},
set(val){
const [str1,str2]=val.split('-')
firstName.value=str1
lastName.value=str2
}
})
function changeFullName(){
fullName.value='li-si'
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
6、watch监视
watch作用:监视数据的变化
watch监视以下四种数据:
- ref定义的数据
- reactive定义的数据
- 函数返回一个值
- 一个包含上述内容的数组
watch(监视对象,回调函数),回调函数:当监视到数据变化后执行的操作或函数
6.1、监视ref定义的基本类型数据
<template>
<!-- html 结构 -->
<div class="person">
<h2>当前求和为{{sum}}</h2>
<button @click="changeSum">sum+1</button>
</div>
</template>
<script setup lang="ts" name="Person111">//相当于setup函数
import { ref,watch} from 'vue'
let sum=ref(0)
function changeSum(){
sum.value+=1
}
const stopWatch= watch(sum,(newVal,oldVal)=>{
console.log('sum变了','原值'+oldVal,'新值'+newVal)
if(newVal>10){//新值大于10解除监视
stopWatch()
}
})
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
6.2、监视ref定义的对象类型数据
直接写数据名,监视的是对象的地址,若想监视对象内部数据,需手动开启深度监视
- 若修改ref定义对象的属性,newValue、oldValue都是新值,因为他们是同一个对象
- 若修改整个ref对象,newValue是新值,oldValue是旧值,因为他们不是同一个对象
watch(被监视的数据、监视的回调、配置对象(deep、immediate等))
immediate:true立即监视并执行watch的回调函数
deep:true开始深度监视,可以监视ref定义对象的属性
<template>
<!-- html 结构 -->
<div class="person">
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改person对象</button>
</div>
</template>
<script setup lang="ts" name="Person111">//相当于setup函数
import { ref,watch} from 'vue'
//数据
let person=ref({
name:'zhangsan',
age:18
})
function changeName(){
person.value.name+='~'
}
function changeAge(){
person.value.age+=1
}
function changePerson(){
person.value={
name:'lisi',
age:100
}
}
watch(person,(newVal ,oldVal)=>{
console.log('person changed',oldVal,newVal)
},{deep:true,immediate:true})
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
6.3、监视reactive定义的对象类型数据
默认开启了深度监视,且无法关闭
<template>
<!-- html 结构 -->
<div class="person">
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<button @click="changeName">修改姓名</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改person对象</button>
</div>
</template>
<script setup lang="ts" name="Person111">//相当于setup函数
import { ref,watch,reactive} from 'vue'
//数据
let person=reactive({
name:'zhangsan',
age:18
})
function changeName(){
person.name+='~'
}
function changeAge(){
person.age+=1
}
// function changePersonRef(){
// person={
// name:'lisi',
// age:100
// }
function changePerson(){
Object.assign(person,{name:'lisi',
age:100})
}
watch(person,(newVal,oldVal)=>{
console.log('person changed',newVal,oldVal)
})
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
6.4、监视ref或reactive定义的对象类型数据中的某个属性
注意:
- 若该属性值不是对象类型,需要写成函数形式
- 若该属性值依然是函数形式,可直接编也可携程函数,建议写成函数
<template>
<!-- html 结构 -->
<div class="person">
<h2>name:{{person.name}}</h2>
<h2>age:{{person.age}}</h2>
<h2>car:{{person.car.c1}}、{{person.car.c2}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changeCar1">修改第一台车</button>
<button @click="changeCar2">修改第二台车</button>
<button @click="changeCar">修改车对象</button>
</div>
</template>
<script setup lang="ts" name="Person111">//相当于setup函数
import { ref,watch,reactive} from 'vue'
let person=reactive({
name:'zhangsan',
age:18,
car:{c1:'benchi',
c2:'bmw'}
})
function changeName(){
person.name+='~'
}
function changeAge(){
person.age+=1
}
function changeCar1(){
person.car.c1='aodi'
}
function changeCar2(){
person.car.c2='dazhong'
}
function changeCar(){
person.car={
c1:'yadi',
c2:'aima'
}
}
watch(()=>{return person.name},()=>{
console.log('name 变化了')
})
//监视的是car内的属性字段,不监视car
watch(person.car,()=>{
console.log('car内的属性字段变化了')
})
//监视的是car,不监视内部字段
watch(()=>person.car,()=>{
console.log('car整体变化了')
})
//监视的是car和监视内部字段
watch(()=>person.car,()=>{
console.log('car变化了')
},{deep:true})
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
6.5、监视上述多个数据
监视第一台车和人的名字
<template>
<!-- html 结构 -->
<div class="person">
<h2>name:{{person.name}}</h2>
<h2>age:{{person.age}}</h2>
<h2>car:{{person.car.c1}}、{{person.car.c2}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changeCar1">修改第一台车</button>
<button @click="changeCar2">修改第二台车</button>
<button @click="changeCar">修改车对象</button>
</div>
</template>
<script setup lang="ts" name="Person111">//相当于setup函数
import { ref,watch,reactive} from 'vue'
let person=reactive({
name:'zhangsan',
age:18,
car:{c1:'benchi',
c2:'bmw'}
})
function changeName(){
person.name+='~'
}
function changeAge(){
person.age+=1
}
function changeCar1(){
person.car.c1='aodi'
}
function changeCar2(){
person.car.c2='dazhong'
}
function changeCar(){
person.car={
c1:'yadi',
c2:'aima'
}
}
watch([()=>person.name,()=>person.car.c1],()=>{
console.log('监视监视第一台车和人的名字')
})
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
6.6、watchEffect
立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行该函数
watch与watchEffect对比:
- 都能监听响应式数据的变化,但监听的方式不同
- watch要明确指出监视的数据
- watchEffect不能明确指出监视的数据
<template>
<!-- html 结构 -->
<div class="person">
<h2>水温为{{temp}}</h2>
<button @click="changeTemp">水温+10</button>
<h2>水位为{{height}}</h2>
<button @click="changeHeight">s水位um+10</button>
</div>
</template>
<script setup lang="ts" name="Person111">//相当于setup函数
import { ref,watch,reactive,watchEffect} from 'vue'
let temp=ref(10)
let height=ref(0)
function changeTemp(){
temp.value+=10
}
function changeHeight(){
height.value+=10
}
watchEffect(()=>{
if(temp.value>=60||height.value>=80){
console.log('告警')
}
})
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
7、ref属性
使用ref进行标记实现单个vue文件内的局部变量
App.vue
<template>//vue3中可以写多个根标签
<Person/>
<Car/>
<h2 ref="title2">nihao</h2>
<button @click="show">输出h2元素</button>
</template>
<script lang="ts" setup name="App">
import Person from './components/Person.vue';
import Car from './components/Car.vue';
import {ref} from 'vue'
//创建一个title2,用于存储ref标记的内容
let title2=ref()
function show(){
console.log(title2.value)
}
</script>
Person.vue
<template>
<!-- html 结构 -->
<div class="person">
<h1>China</h1>
<h2 ref="title2">Beijing</h2>
<h3>People</h3>
<button @click="show">输出h2元素</button>
</div>
</template>
<script setup lang="ts" name="Person111">//相当于setup函数
import { ref,watch,reactive,watchEffect} from 'vue'
//创建一个title2,用于存储ref标记的内容
let title2=ref()
function show(){
console.log(title2.value)
}
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
8、props
9、组件的生命周期
9.1、阶段
vue2
创建(创建前beforeCreate,创建完created毕)
挂载(挂载前beforeMount,挂载完毕mounted)
更新(更新前beforeUpdate,更新完毕updated)
销毁(销毁前beforeDestroy,销毁完毕destroyed)
vue3
创建(创建前setup)
挂载(挂载前onBeforeMount,挂载完毕onMounted)
更新(更新前onBeforeUpdate,更新完毕onUpdated)
销毁(销毁前onBeforeUnmount,销毁完毕onUnmounted)
子先与父挂载
<template>//vue3中可以写多个根标签
<Person v-if="isShow"/>
<dtest/>
</template>
<script lang="ts" setup name="App">
import Person from './components/Person.vue';
import dtest from './components/dtest.vue'
import Car from './components/Car.vue';
import {ref,onMounted} from 'vue'
let isShow=true//改为false
onMounted(()=>{
console.log('父-----挂载完毕')
})
</script>
<template>
<!-- html 结构 -->
<div class="person">
<h2>{{sum}}</h2>
<button @click="add">sum+1</button>
</div>
</template>
<script setup lang="ts" name="Person">//相当于setup函数
import { ref,watch,reactive,watchEffect,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,
onBeforeUnmount,onUnmounted} from 'vue'
import {type PersonInter} from '@/types/index'
import {defineProps} from 'vue'
let sum=ref(0)
function add(){
sum.value+=1
}
console.log('创建')
onBeforeMount(()=>{
console.log('挂载前')
})
onMounted(()=>{
console.log('子-----挂载完毕')
})
onBeforeUpdate(()=>{
console.log('更新前')})
onUpdated(()=>{
console.log('更新完毕')})
onBeforeUnmount(()=>{
console.log('卸载前')})
onUnmounted(()=>{
console.log('卸载完毕')})
</script>
<style scoped>
.person{
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button{
margin: 0 5px;
}
</style>
10、路由
通过不同网址得到不同的页面效果
App.vue
<template>
<!-- vue3中可以写多个根标签 -->
<div class="app">
<h2 class="title">Vue路由测试</h2>
<!-- 导航区 -->
<div class="navigate">
<RouterLink to="/home" active-class="active">首页</RouterLink>
<RouterLink to="news" active-class="active">新闻</RouterLink>
<RouterLink to="about" active-class="active">关于</RouterLink>
</div>
<!-- 展示区 -->
<div class="main-content">
<RouterView></RouterView>
</div>
</div>
</template>
<script lang="ts" setup name="App">
import {RouterView,RouterLink} from 'vue-router'
</script>
<style>
.title{
text-align: center;
word-spacing: 5px;
margin: 30px 0;
height: 70px;
line-height: 70px;
background-image: linear-gradient(45deg,gray,white);
border-radius: 0 0 2px;
box-shadow: 0 0 2px;
font-size: 30px;
}
.navigate{
display: flex;
justify-content: space-around;
margin: 0 100px;
}
.navigate a {
display: block;
text-align: center;
width: 90px;
height: 40px;
line-height: 40px;
background-color: gray;
text-decoration: none;
color: white;
font-size: 18px;
letter-spacing: 5px;
}
.navigate a.active{
background-color: #64967E;
color: #ffc268;
font-weight: 900;
text-shadow: 0 0 1px black;
font-family: 微软雅黑;
}
.main-content{
margin: 0 auto;
margin-top: 30px;
border-radius: 10px;
width: 90%;
height: 400px;
border: 1px solid;
}
</style>
components中的vue
- About.vue
<template>
<div class="about">
<h2>大家好</h2>
</div>
</template>
<script setup lang="ts" name="About"></script>
- Home.vue
<template>
<div>
<img src="https://pica.zhimg.com/v2-cfedab8366d4b9d691a69716fb0c31c4_qhd.jpg?source=7e7ef6e2" alt="">
</div>
</template>
<script setup lang="ts" name="Home"></script>
<style scoped>
.home{
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
</style>
- News.vue
<template>
<div class="news">
<ul>
<li><a href="#">001</a></li>
<li><a href="#">002</a></li>
<li><a href="#">003</a></li>
<li><a href="#">004</a></li>
<li><a href="#">005</a></li>
</ul>
</div>
</template>
<script setup lang="ts" name="News"></script>
编写路由index.ts
//创建一个路由器并暴露出去
import {createRouter,createWebHistory} from 'vue-router'
import Home from '@/components/Home.vue'
import News from '@/components/News.vue'
import About from '@/components/About.vue'
//创建路由
const router=createRouter({
history:createWebHistory(),
routes:[
{
path:'/home',
component:Home
},
{
path:'/news',
component:News
},
{
path:'/about',
component:About
}
]
})
export default router
注意点:
- 路由组件一般存在pages或views文件夹,一般组件放在components文件夹
- 通过点击导航,视觉效果上”卸载“了的路由组件默认是被销毁了,需要的时候再去挂载。
10.1 路由器工作模式
- history模式
vue2:mode:’history’
vue3: history:createWebHistory()
React:BrowserRouter
URL更加美观,网址没有#。但后期项目上线,需要服务端配合处理路径问题,否则刷新会有404
- hash模式
兼容性好,服务端不用处理路径。URL带有#不美观,且在SEO优化方面相对较差。
10.2 to的两种写法
-
<RouterLink to="/home" active-class="active">首页</RouterLink>
-
<RouterLink :to="{path:'/home'}" active-class="active">首页</RouterLink>
10.3 路由命名
//创建一个路由器并暴露出去
import {createRouter,createWebHistory} from 'vue-router'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import About from '@/pages/About.vue'
//创建路由
const router=createRouter({
history:createWebHistory(),
routes:[
{
name:'zhuye',
path:'/home',
component:Home
},
{
name:'xinwen',
path:'/news',
component:News
},
{
name:'guanyu',
path:'/about',
component:About
}
]
})
export default router
<div class="navigate">
<RouterLink to="/home" active-class="active">首页</RouterLink>
<RouterLink :to="{name:'xinwen'}" active-class="active">新闻</RouterLink>
<RouterLink :to="{path:'/about'}" active-class="active">关于</RouterLink>
</div>
10.4 嵌套路由
news中嵌套detail,即/news/detail
index.ts
//创建一个路由器并暴露出去
import {createRouter,createWebHistory} from 'vue-router'
import Home from '@/pages/Home.vue'
import News from '@/pages/News.vue'
import About from '@/pages/About.vue'
import Detail from '@/pages/Detail.vue'
//创建路由
const router=createRouter({
history:createWebHistory(),
routes:[
{
name:'zhuye',
path:'/home',
component:Home
},
{
name:'xinwen',
path:'/news',
component:News,
children:[
{
path:'detail',
component:Detail
}
]
},
{
name:'guanyu',
path:'/about',
component:About
}
]
})
export default router
news.vue
<template>
<div class="news">
<!-- news的导航区 -->
<ul>
<!-- <li><a href="#">001</a></li>
<li><a href="#">002</a></li>
<li><a href="#">003</a></li>
<li><a href="#">004</a></li>
<li><a href="#">005</a></li> -->
<li v-for="news in newList" :key="news.id">
<RouterLink to="/news/detail">{{ news.titile }}</RouterLink>
</li>
</ul>
<!-- news的展示区 -->
<div class="new-contents"></div>
<RouterView></RouterView>
</div>
</template>
<script setup lang="ts" name="News">
import {reactive} from 'vue'
import {RouterView} from 'vue-router'
const newList=reactive([
{id:'01',titile:'titile1',content:'aaa'},
{id:'02',titile:'titile2',content:'bbb'},
{id:'03',titile:'titile3',content:'ccc'},
{id:'04',titile:'titile4',content:'ddd'}
])
</script>
detail.vue
<template>
<ul class="new-list">
<li>编号:xxx</li>
<li>标题:xxx</li>
<li>内容:xxx</li>
</ul>
</template>
<script setup lang="ts " name="About"></script>
<style scoped>
.new-list{
list-style: none;
padding-left: 20px;
}
.new-list>li{
line-height: 30px;
}
</style>