Vue3基础

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定义的对象类型数据中的某个属性

注意:

  1. 若该属性值不是对象类型,需要写成函数形式
  2. 若该属性值依然是函数形式,可直接编也可携程函数,建议写成函数
<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

注意点:

  1. 路由组件一般存在pages或views文件夹,一般组件放在components文件夹
  2. 通过点击导航,视觉效果上”卸载“了的路由组件默认是被销毁了,需要的时候再去挂载。
10.1 路由器工作模式
  • history模式

vue2:mode:’history’

vue3: history:createWebHistory()

React:BrowserRouter

URL更加美观,网址没有#。但后期项目上线,需要服务端配合处理路径问题,否则刷新会有404

  • hash模式

兼容性好,服务端不用处理路径。URL带有#不美观,且在SEO优化方面相对较差。

10.2 to的两种写法
  1. <RouterLink to="/home" active-class="active">首页</RouterLink>
    
  2. <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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空指针异常Null_Point_Ex

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值