vue3初始化工程目录
编写一个App
.vscode下的extensions.json
配置插件的地方
public
页签图标
src
你的.vue文件都是在这个目录下的
.gitgnore
忽略文件
env.d.ts
让Ts去识别一些文件
index.html
入口文件
vite.config.ts
整个工程的配置文件
.vue文件中可以写的内容 template(结构标签) script(脚本标签 js/ts) style(样式)
<!-- template(结构标签) script(脚本标签 js/ts) style(样式) --><template><div class="app"><h1>你好啊</h1></div>
</template><script lang="ts">export default{name:'app' // 组件的名子}
</script><style>.app{background-color: antiquewhite;box-shadow: 0 0 10px;border-radius: 10px;padding: 20px;}
</style>
main.ts文件
// 引入crerateApp用来创建应用
import {createApp} from 'vue'
// 引入App根组件
import App from './App.vue'createApp(App).mount('#app')
OptionsApi 与 CompositionApi (setup)
什么是选项式(vue2),什么是组合式(vue3)
// 选项式 vue2<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<button @click="changeName">修改名子</button>
<button @click="changeAge">修改年龄</button>
<button @click="showTel">电话</button>export default{name:'Person',data(){return{// 数据name:'张三',age:18, tel:'124345555'}},methods:{// 方法changeName(){this.name = 'zhang-san'},changeAge(){this.age += 1},showTel(){alert(this.tel)}},// 组合式 vue3<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<button @click="changeName">修改名子</button>
<button @click="changeAge">修改年龄</button>
<button @click="showTel">电话</button>export default{name:'Person',setup(){// 数据let name = '张三' // 这样写name不是响应式的let age = 18let tel = 12388889999// 方法function changeName(){name = 'zhang-san'}function changeAge(){age += 1}function showTel(){alert(tel)}// 最后把数据交出去return {name,age,changeName,changeAge,showTel}// setup的返回值也可以是一个渲染的函数return ()=> 'hh'}}
setup 语法糖
<script setup lang="ts">
// 相当于setup 并且会自动retrun let a = '李四'let b = 29let tel = 1238888888
</script>
ref基本类型的响应式数据
注:erf还可以定义对象类型的响应式数据
<template><div class="person"><!-- 这里可以不用.value --><h2>姓名:{{ name }}</h2><h2>年龄:{{ age }}</h2><button @click="changeName">修改名子</button><button @click="changeAge">修改年龄</button><button @click="showTel">电话</button></div>
</template><script setup lang="ts"> import {ref} from 'vue' // 想让那个数据是响应式的就用ref包一下let name = ref('李四') // 变成响应式数据let age = ref(18)let tel = 1238888888 function changeName(){// 在ts/js中操作响应式数据要加上.valuename.value = 'zhang-san'}function changeAge(){age.value += 1}function showTel(){alert(this.tel)}
</script>
reactive对象类型的响应式数据
注:reactive只能定义对象类型的数据
<template><div class="person"><h2>一辆{{ car.brand }}车,价值{{ car.price }}</h2><button @click="changePrice">修改汽车的价格</button></div>
</template><script setup lang="ts"> import {reactive} from 'vue' // 想让那个数据是响应式的就用ref包一下// 可以使用reflet car = reactive({brand:"奔驰",price:200}) // 把对象数据用reactive包裹起来function changePrice(){car.price += 10}//同样可以让数组变成响应式let games = reactive([ {id: 1, name: 'LOL'},{id: 2, name: 'CSGO'},{id: 3, name: 'DOTA2'},])</script>
reactive的局限性(在重新分配一个对象的时候会失去响应式
)
let games = reactive([ {id: 1, name: 'LOL'},{id: 2, name: 'CSGO'},{id: 3, name: 'DOTA2'},])// 重新分配一个对象 这时games就不再是一个响应式的对象了function changeCar(){games = [{id: 3,name: 'LOL'}]}// 可以使用Object.assign(obj1,obj2,obj3)Object.assign(games,games = [{id: 3,name: 'LOL'}])
ref定义对象类型的响应式数据
如果想要ref定义对象类型的响应式数据,需要使用.value来拿到对象
注:ref不能定义多次响应式对象或基本类型
<script setup lang="ts"> import {ref} from 'vue' // 想让那个数据是响应式的就用ref包一下let games = ref([ {id: 1, name: 'LOL'},{id: 2, name: 'CSGO'},{id: 3, name: 'DOTA2'},])function changeGame (){// 用ref定义响应式的数据需要在对象的后面.value 拿到这个对象games.value[0].name = 'LOL2';}// ref可以直接修改整个对象 这样改完后还是响应式对象function changeRef(){games = {[id:4,name:'赛博朋克2077']} // reactive 不能这样}
</script>
可以发现ref的value不再是基本类型,而是Proxy类型 (底层通过reactive来处理
)
选择
- 若需要一个基本类型的响应式数据必须用
ref
- 若需要一个响应式对象,层级不深
ref
reactive
都可以 - 若需要一个响应式对象,且层级较深,推荐使用
reactive
toRefs 与 toRef
toRefs就是把所定义的对象变成ref所组成的响应式的数据,toRef一个个的去取变成响应式数据
<script setup lang="ts">
import {ref,reactive, toRef, toRefs } from 'vue' // 数据let Person = reactive({name:'张三',age:18,sex:'男',})// 使用toRefs让所有数据变成响应式的数据let {name,age,sex} = toRefs(Person)// 使用toRef就是把其中一个拧出来变成响应式的数据let {name,age,sex} = toRef(Person,'sex')</script>
Computed计算属性
计算属性的特点依赖的数据只要发生变化 ,就会重新计算
注:计算属性是有缓存的,只要依赖的数据没有发生变化就不会重新计算,方法就没有缓存
<template><div class="person">姓名:<input type="text" v-model="firstNanme"><br> 名字:<input type="text" v-model="lastName"><br>全名:<span>{{ fullName }}</span><button @click="changeFullName">修改</button></div>
</template><script setup lang="ts">
import {ref,computed} from 'vue' // 引入computed来计算属性
let firstNanme = ref('张')
let lastName = ref('三')// 这么定义的fullName计算属性是一个只读的,不可修改
// let fullName = computed(()=>{
// return firstNanme.value + lastName.value
// })// 这么定义的fullName计算属性是可读可写的
let fullName = computed({get(){return firstNanme.value.slice(0,1).toUpperCase + firstNanme.value.slice(1) + '-' + lastName.value },// 这里的valchangeFullName给的值set(val){const [str1,str2] = val.split('-')firstNanme.value = str1lastName.value = str2}
})// 这里把值给到fullName要通过get/set的方式来让它变成可读可改的数据
function changeFullName(){fullName.value = '李四'
}</script>
watch监视
vue3
中的watch
只能监视以下四种数据
ref
定义的数据reactive
定义的数据- 函数返回一个值(
getter
函数) - 一个包含上述内容的数组
情况:1
<template><div class="person"><h1>情况一:监视ref定义的基本类型数据</h1><h2>当前求和为:{{ sum }}</h2> </div><button @click="changeSum">点我sum+1</button>
</template><script setup lang="ts">
import {ref,watch} from 'vue' // 数据
let sum = ref(0)// 方法
function changeSum(){return sum.value += 1
}// 监视 监视ref定义的基本类型数据
const stopWatch = watch(sum,(newVaule,oldValue)=>{console.log(newVaule,oldValue)if(newVaule >= 0){// watch有一个返回方法,调用后就会停止监视stopWatch()}
})
</script>
情况:2
监视 ref
定义的 对象类型
数据
注意:
- 若修改的是
ref
定义的对象中的属性,newValue
和oldValue
都是新值,因为它们是同一个对象- 若修改的是整个
ref
定义的对象,newValue
是新值oldValue
是旧值
<template><div class="person"><h1>情况二:监视ref定义的对象类型数据</h1><h2>姓名:{{ person.name }}</h2> <h2>年龄:{{ person.age }}</h2> </div><button @click="changeName">点我姓名</button><button @click="changeAge">点我修改年龄</button><button @click="changePerson">点我修改整个对象</button>
</template><script setup lang="ts">
import {ref,watch} from 'vue' // 数据
let person = ref({name:'张三',age:18
})// 方法
function changeName(){person.value.name += '~'
}
function changeAge(){person.value.age += 1
}
function changePerson(){person.value = {name:'李四',age:20}
}// 情况二:监视的是对象的地址值,若想监视对象内部属性的变化,需要手动开启深度监视
// 参数一:被监视的数据
// 参数二:监视的回调
// 参数三:配置对象(deep,immediate...)
watch(person,(newVaule,oldValue)=>{console.log(newVaule,oldValue)
},{deep:true}) // deep:true 开启深度监视
</script>
情况:3
监视 reactive
定义的 对象类型
数据
监视
reactive
定义的对象类型数据,默认
是开启深度监视
,并且无法关闭
<template><div class="person"><h1>情况三:监视reactive定义的对象类型数据</h1><h2>姓名:{{ person.name }}</h2> <h2>年龄:{{ person.age }}</h2> </div><button @click="changeName">点我姓名</button><button @click="changeAge">点我修改年龄</button><button @click="changePerson">点我修改整个对象</button>
</template><script setup lang="ts">
import {reactive,watch} from 'vue' // 数据
let person = reactive({name:'张三',age:18
})// 方法
function changeName(){person.name += '~'
}
function changeAge(){person.age += 1
}// 无法直接用对象赋值的方式
function changePerson(){Object.assign(person,{name:'李四',age:20})
}// 情况三:监视reactive定义的对象类型数据,默认是开启深度监视,并且无法关闭
watch(person,(newVaule,oldValue)=>{console.log(newVaule,oldValue)
},{deep:false}) // 无法关闭
</script>
情况:4
监视 reactive
定义的 对象类型
数据中的 某个属性
注意:
- 若该属性值
不是
对象类型,需要写成函数形式
- 若该属性值
依然
是对象类型
,建议写成函数形式
,并开启深度监视
<template><div class="person"><h1>情况四:监视reactive定义的对象类型数据中的某个属性</h1><h2>姓名:{{ person.name }}</h2> <h2>年龄:{{ person.age }}</h2><h2>气辆:{{ person.car.c1 }},{{ person.car.c2 }}</h2></div><button @click="changeName">点我修改姓名</button><button @click="changeAge">点我修改年龄</button><button @click="changeCar1">点我修改第一台车</button><button @click="changeCar2">点我修改第二台车</button><button @click="changeCarAll">点我修改整台车</button>
</template><script setup lang="ts">
import {reactive,watch} from 'vue' // 数据
let person = reactive({name:'张三',age:18,car:{c1:'奔驰',c2:'宝马'}
})// 方法
function changeName(){person.name += '~'
}
function changeAge(){person.age += 1
}
function changeCar1(){person.car.c1 = 'BYD'
}
function changeCar2(){person.car.c2 = "小米"
}
function changeCarAll(){person.car = {c1:'华为',c2:'蔚来'}
}// 情况四:监视reactive定义的对象类型数据中的某个属性,且该属性是基本类型的,要写成函数式
watch(()=>person.name,()=>{console.log('name改变啦')
})// 这样写就相当于监视的是这个函数的地址值// 只要是监视对象中的某个属性,就直接写函数式
watch(()=>person.car,()=>{console.log('car改变啦')
},{deep:true})</script>
情况:5
监视上述的多个数据
<template><div class="person"><h1>情况五:监视上述的多个数据</h1><h2>姓名:{{ person.name }}</h2> <h2>年龄:{{ person.age }}</h2><h2>气辆:{{ person.car.c1 }},{{ person.car.c2 }}</h2></div><button @click="changeName">点我修改姓名</button><button @click="changeAge">点我修改年龄</button><button @click="changeCar1">点我修改第一台车</button><button @click="changeCar2">点我修改第二台车</button><button @click="changeCarAll">点我修改整台车</button>
</template><script setup lang="ts">
import {reactive,watch} from 'vue' // 数据
let person = reactive({name:'张三',age:18,car:{c1:'奔驰',c2:'宝马'}
})// 方法
function changeName(){person.name += '~'
}
function changeAge(){person.age += 1
}
function changeCar1(){person.car.c1 = 'BYD'
}
function changeCar2(){person.car.c2 = "小米"
}
function changeCarAll(){person.car = {c1:'华为',c2:'蔚来'}
}//情况五:监视上述的多个数据,用数组包起来,并且里面都要写成函数式
watch([()=>person.name,()=>person.age,()=>person.car.c1,()=>person.car.c2],(newValue,oldValue)=>{console.log(newValue,oldValue)
},{deep:true
})</script>
watchEffect
watch 对比 watchEffect
watch
:要明确指出监视的数据watchEffect
:不用明确指出监视的数据(函数中用到哪些属性,那就监视哪些属性)
<template><div class="person"><h2>当前水温:{{temp }}</h2> <h2>当前水位:{{height }}</h2> <button @click="changeSum">点我sum加一</button><button @click="changeHeight">点我height加一</button></div>
</template><script setup lang="ts">
import {ref,watch,watchEffect} from 'vue' // watchEffect用来明确监视某个变量的变化// 数据
let temp = ref(0)
let height = ref(0)// 方法
function changeSum(){temp.value += 10
}function changeHeight(){height.value += 10
}// 监视 watch实现
watch([temp,height],(value)=>{let [newTemp,newHeight] = valueif(newTemp > 100 || newHeight > 100){alert('当前温度或水位过高')}
})// 监视 watchEffect实现
watchEffect(()=>{if(temp.value > 100 || height.value > 100){alert('当前温度或水位过高')}
})
</script>
标签的ref属性
注意:
- 可以用在普通的html标签上,也可以用在组件标签上
- 普通的
html
拿到的是dom元素
,组件
拿到的是组件实例对象
<template><div class="person"><h2 ref="title2">中国</h2> <h2>北京</h2> <button @click="showLog">点我输出h2这个元素</button></div>
</template><script setup lang="ts"> import { ref,defineExpose } from 'vue'// 创建一个title2 ,用于存储ref标记的内容let title2 = ref()let a = ref()let b = ref()let c = ref()function showLog(){console.log(title2.value)}// 表示给父组件使用defineExpose({a,b,c})
</script>
自定义类型 接口 泛型 (ts)
// ts
// 定义一个接口,用于限制person对象的具体属性
export interface PersonInterFace {id:stringname: stringage: number
}// 一个自定义类型 export用来交出去
export type PersonList = Array<PersonInterFace>// vue
<script setup lang="ts"> // 前面要加上typeimport {type PersonInterFace,type PersonList} from '@/types'// 限制类中的成员let person:PersonInterFace = {id:'ayusaaa',name:'张三',age:20}// 一个数组里面是PersonInterFacelet personlist:PersonList = [{id:'ayusaaa',name:'张三',age:20},{id:'ayusaaa',name:'张三',age:20},{id:'ayusaaa',name:'张三',age:20}]
</script>
Props的使用
// ts
// 定义一个接口,用于限制person对象的具体属性
export interface PersonInterFace {id:stringname: stringage: number// 在使用时加?表示可选属性num?:number
}// 一个自定义类型 export用来交出去
export type PersonList = Array<PersonInterFace>// vue
<template><!-- :list 把personList当做一个变量 加上:就相当于表达式会做运算,否则就是字符串--><Person a="hh" :list="personList" />
</template><script lang="ts" setup>import Person from './components/Person.vue'; // 枝import { ref } from 'vue';import { type PersonList } from './types';// ref可以通过传入泛型的方式来限制其中的属性成员let personList = ref<PersonList>([{id:'ayusaaa',name:'张三',age:20},{id:'ayusaaa',name:'张三',age:20},{id:'ayusaaa',name:'张三',age:20}])</script>// App.vue
<template><div class="person"><!-- <h2>{{ a }}</h2> --><ul><!-- :key就相当于去读取每个item中的唯一的id --><!-- v-for不仅可以写数组还可以写次数 --><li v-for="item in list" :key="item.id">{{ item }}</li></ul></div>
</template>// Person.vue
<script setup lang="ts"> import { defineProps,withDefaults } from 'vue'; // withDefaults默认值import { type PersonList } from '@/types';// 从外部组件接收一个对象a,list// defineProps(['a','list'])// 接收list,同时将props保存起来// let x = defineProps(['list'])// 接收list,同时限制类型// defineProps<{list:PersonList}>()// 接口list,同时限制类型,限制必要性,指定默认值withDefaults(defineProps<{list?:PersonList}>(),{// 设置默认认值list:()=> [{id:"aaa",name:'bbb',age:98}]})</script>
Vue的生命周期
组件的生命周期:
- 创建
- 挂载
- 更新
- 销毁
Vue2的生命周期:
4个接阶段,8个状态
创建(创建前 beforeCreate
,创建完毕 created
)
挂载(挂载前 beforeMount
,挂载完毕 mounted
)
更新(更新前 beforeUpdate
,更新完毕 updated
)
销毁(销毁前 beforeDestroy
,销毁完毕 destroyed
)
Vue3的生命周期:
4个接阶段,8个状态
创建(创建前 setup
,创建完毕 setup
)
挂载(挂载前 onBeforeMount
,挂载完毕 onMounted
)
更新(更新前 onBeforeUpdate
,更新完毕 onUpdated
)
卸载(卸载前 onBeforeUnmount
,卸载完毕 onUnmounted
)
父组件和子组件的生命周期
子组件优先执行,最后是父组件
<template><div class="person"><h2>当前的求和为:{{ sum }}</h2><button @click="sumAdd">+</button></div>
</template><script setup lang="ts">import {ref,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted} from 'vue'// 创建let sum = ref(0)// 方法function sumAdd(){sum.value += 1 }// 创建console.log('这里就是创建,setup就是在为我们做创建的工作')// 挂载前onBeforeMount(()=>{console.log("挂载前")})// 挂载完毕onMounted(()=>{console.log("挂载完毕")})// 更新前onBeforeUpdate(()=>{console.log('更新前')})// 更新完毕onUpdated(()=>{console.log('更新完毕')})// 卸载前onBeforeUnmount(()=>{console.log('卸载前')})// 卸载完毕onUnmounted(()=>{console.log('卸载完毕')})
</script>
自定义Hooks
命名规范:use后面跟功能名称
hooks就是把相同功能的方法和数据封装到一个文件中(可以是ts,也可以是js)
useDog.ts
import {ref} from 'vue'
import axios from 'axios'export default function (){// 只包含和useDog相关的变量和方法let dogList = ref(['aaa'])// 方法async function getDog(){let result = await axios.get('https://dog.ceo/api/breeds/image/random')dogList.value.push(result.data.message)}// 向外部提供数据return {dogList,getDog}
}
useSum.ts
import {ref} from 'vue'export default function useSum(){// 数据let sum = ref(0)// 方法function sumAdd(){sum.value += 1 }return {sum,sumAdd}// 向外提供数据和方法return {sum,sumAdd}
}
在Person中就可以直接使用了
<script setup lang="ts">// 导入这两个文件import useDog from '@/hooks/useDog';import useSum from '@/hooks/useSum';// 可以直接调用这个方法来获取他导出的数据const { sum, sumAdd } = useSum();const { dogList, getDog } = useDog();
</script>
路由
路由的基本效果
注意点:
一般组件:
亲手写的标签出来的(一般放在components文件夹当中)
路由组件:
靠路由的规则渲染出来的(一般放在pages/views文件夹当中)
main.ts
// main.ts
// 引入crerateApp用来创建应用
import {createApp} from 'vue'
// 引入App根组件
import App from './App.vue'
// 引入路由器
import router from './router'
// 创建一个应用
const app = createApp(App)
// 使用路由器
app.use(router)
// 挂载整个应用到app容器中
app.mount('#app')
App.vue
// App.vue
<template><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>import { RouterView } from 'vue-router';
</script>
router.ts
//router.ts
// 引入 createRouter
import {createRouter,createWebHashHistory} 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:createWebHashHistory(),routes:[{path:'/home/',component:Home},{path:'/news/',component:News},{path:'/about/',component:About}]}
)// 暴露出去
export default router
路由器的工作模式
history模式
优点:
URL
更加美观,不带有#
号
缺点:后期项目上线,需要服务端配合处理路径问题,否则刷新会有404
错误const router = createRouter({ // history模式history:createWebHistory() })
hash模式
优点:兼容性更好,不需要服务器端处理路径
缺点:URL
带有#
号,不太美观,并且在SEO
优化方面相对较差const router = createRouter({ // Hash模式history:createWebHashHistory() })
to的两种写法
// 第一种:to的字符串
<RouterLink to="/home" active-class="active">首页</RouterLink>
// 第二种:to的对象
<RouterLink :to="{path:'/home'}" active-class="active">首页</RouterLink>
命名路由
// 通过名称来路由
...
{name:'zhuye',path:'/home/',component:Home
}
...
<RouterLink :to="{name:'zhuye'}" active-class="active">主页</RouterLink>
嵌套路由
// 创建路由器
const router = createRouter({// 路由器的工作模式history:createWebHistory(),routes:[{name:'zhuye',path:'/home/',component:Home},{name:'xinwen',path:'/news/',component:News,children:[{path:'detail',component:Detail}]},{path:'/about/',component:About}]}
)
路由传参
注1:使用 params 参数时,若使用 ot 的对象写法,必须使用 name 配置项,不能使用 path
注2:使用 params 参数时,需要提前在规则中占位
路由的传参有两种形式
query
params
query的方式传参
// query第一种写法:
// 普通的传参方式
<RouterLink to="/news/detail?id=3&title=哈哈&content=无">{{ item.title }}</RouterLink>
// 使用模板字符串进行传参
<RouterLink :to="`/news/detail?id=${item.id}&title=${item.title}`">{{ item.title }}</RouterLink>// query第二种写法:
<RouterLink
:to="{path:'news/detail',query:{id:item.id,title:item.title}}"
>{{ item.title }}
</RouterLink>
params的方式传参
// params第一种的写法
// 这里的哈哈/嘿嘿/了了将做为参数进行传递
<RouterLink to="/news/detail/哈哈/嘿嘿/了了">{{ item.title }}</RouterLink>routes:[{name:'zhuye',path:'/home/',component:Home},{name:'xinwen',path:'/news/',component:News,children:[{name:'xiangqin'// 使用params的方式传参需要在这里进行占位,占位符可以是任意字符串(如果有些参数是可传可不传的可以在后面加个问号) 参数的必要性path:'detail/:x/:y/:z?',component:Detail}]},{path:'/about/',component:About}]// params第二种写法:
<RouterLink
:to="{// 这里就不能用path来接收路由了,要使用namename:'xiangqin',query:{id:item.id,title:item.title}}"
>{{ item.title }}
</RouterLink>
路由的Props配置
{name:'xinwen',path:'/news/',component:News,children:[{name:'xiangqin',// 使用params的方式传参需要在这里进行占位,占位符可以是任意字符串path:'detail/:x/:y/:z',component:Detail,// 第一种写法 表示直接把path上的占位符参数给传递过去(只能处理params参数)props:true// 第二种写法 函数写法,可以自己决定将什么作为props给路由组件props(route){return route.query}// 第三种写法 对象写法,可以自己决定将什么作为props给路由组件props:{a:100,b:200,c:300}}]
},<template><ul class="news-list"><li>{{ x }}</li><li>{{ y }}</li></ul>
</template><script setup lang="ts" name="Detail">//这里就可以使用defineProps来接收defineProps(['x','y','z'])
</script>
路由replace属性
路由默认
每次跳转都是push的模式
// 在RouterLink 上添加replace就把push改为replace模式了<RouterLink replace to="/home" active-class="active">首页</RouterLink><RouterLink replace :to="{name:'xinwen'}" active-class="active">新闻</RouterLink><RouterLink replace :to="{path:'/about'}" active-class="active">关于</RouterLink>
编程式路由导航
简单写法
<script setup lang="ts" name="Home">import {onMounted} from "vue";import {useRouter} from "vue-router";const router = useRouter();onMounted(()=>{setTimeout(()=>{// 通过路由属性中的push进行跳转router.push("/news");},3000)})</script>
对象写法
<script setup lang="ts" name="Home">import {onMounted} from "vue";import {useRouter} from "vue-router";const router = useRouter();function showNewDetail(new:any){router.push({name:'xing',query:{new.id,new.title,new.content}})}</script>
路由重定向
在路由规则最后一个加上
{path:'/',// 重定向redirect:'/home/'}