Vue路由的分类与使用
watchEffect
立即运行一个函数,同时响应式的追踪其依赖,并重新执行函数
<template>
<div>
<h1>{{ num1 }} + {{ num2 }} = {{ num1 + num2 }}</h1>
<button @click="changeNum1">num1++</button>
<button @click="changeNum2">num2++</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref, watch, watchEffect} from "vue";
let num1 = ref(1);
let num2 = ref(3);
const changeNum1 = () => {
num1.value += 1;
}
const changeNum2 = () => {
num2.value += 1;
}
/*watch([num1, num2], (value) => {
const [newNum1, newNum2] = value;
console.log(newNum1, newNum2)
if (newNum1 == 5 || newNum2 == 7) {
console.log("数据到达");
}
})*/
const stopWatch = watchEffect(() => {
console.log(num1.value,num2.value)
if (num1.value == 5 || num2.value == 7) {
console.log("数据到达,停止监视");
stopWatch();
}
})
</script>
<style scoped>
</style>
标签ref属性
作用 在普通的DOM上 获取DOM节点,用在组件上 获取组件实例
用于DOM 获取节点
<h1 ref="title1">猿究院</h1>
<h1 ref="title2">北大街</h1>
<h1 ref="title3">Vue</h1>
<input type="text" value="默认值" ref="ipt"/>
let title1 = ref();
let title2 = ref();
let title3 = ref();
let ipt = ref();
const showLog = () => {
console.log(title1.value)
console.log(title2.value)
console.log(title3.value)
//ipt > RefImpl >value <input 对象 .value
console.log(ipt.value.value)
}
ref作用于组件上
<Message ref="msg"></Message>
********* 子组件中
//使用defineExpose将组件的数据交给外部组件
defineExpose({title, desc})
*********
let msg = ref();
const getMessage = () => {
console.log(msg.value.title)
console.log(msg.value.desc)
}
props
<template>
<Person :list="persons"></Person>
</template>
<script lang="ts" setup name="App">
import Person from "@/components/Person.vue";
import {reactive} from "vue";
import type {Persons} from "@/assets/IPersonInter";
import {nanoid} from "nanoid";
let persons = reactive<Persons>([
{id: nanoid(), name: '张三', age: 20},
{id: nanoid(), name: '李四', age: 19},
{id: nanoid(), name: '王五', age: 25}
])
</script>
<style lang="scss" scoped>
</style>
<template>
<ul v-if="list != undefined">
<li v-for="(p,index) in list" :key="p.id">
{{ p.name }} - {{ p.age }}
</li>
</ul>
<div v-else>
暂无数据
</div>
</template>
<script lang="ts" setup name="Person">
import type {Persons} from "@/assets/IPersonInter";
//第一种写法
// const props = defineProps(['list']);
//第二种写法 接收 + 限制类型
// const props =defineProps<{list:Persons}>();
//第三种写法 接收 + 限制类型 + 指定默认值+限制必要性 (? 可以传 可不传)
const props = withDefaults(defineProps<{ list?: Persons }>(), {
list: () => [{id: "001", name: '默认值', age: 0}]
});
//在setup中使用 接收到的数据时 需要通过 props对象 .
console.log(props.list)
</script>
<style scoped>
</style>
自定义的hook
本质是一个函数,把setup中的 组合式 API进行封装。
hook 优势:让代码复用 ,让setup中的逻辑更清楚。
useDog.ts
import {onMounted, reactive} from "vue";
import axios, {AxiosError} from "axios";
export default function () {
let dogList = reactive<string[]>([])
async function getDog() {
//发送请求
try {
let {data} = await axios.get("https://dog.ceo/api/breed/weimaraner/images/random");
console.log("请求的结果:", data);
dogList.push(data.message)
} catch (error) {
const err = <AxiosError>error;
console.log(err.message)
}
}
onMounted(() => {
getDog();
})
return {dogList, getDog}
}
useSum.ts
import {ref, onMounted} from 'vue'
export default function () {
let sum = ref(0);
const increment = () => {
sum.value += 1;
}
const decrement = () => {
sum.value -= 1;
}
onMounted(() => {
console.log("执行了useSum的onMounted")
increment();
})
//向外暴露数据
return {sum, increment, decrement}
}
Person.vue
<template>
<h2>当前求和:{{ sum }}</h2>
<button @click="increment">点我+1</button>
<button @click="decrement">点我-1</button>
<hr/>
<button @click="getDog">再来一直狗子</button>
<img style="width: 200px;" :src="(dog as string)" v-for="(dog,index) in dogList" :key="index">
</template>
<script lang="ts" setup name="Person">
import useSum from "@/assets/useSum";
import {onMounted} from "vue";
import useDog from "@/assets/useDog";
let {sum, increment, decrement} = useSum();
let {dogList, getDog} = useDog();
onMounted(() => {
console.log("我是person组件的onMounted")
})
</script>
<style scoped>
</style>
路由
1.安装 npm install vue-router@4
2.使用 在 src/router/index.ts文件
import {createRouter, createWebHistory} from 'vue-router'
//被路由的组件
import Home from "@/components/Home.vue";
import About from "@/components/About.vue";
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: "/", 默认访问
component: Home
},
{
path: '/home',
component: Home
},
{
path: '/about',
component: About
}
]
})
export default router;
<!-- 声明式路由 -->
<RouterLink to="/home">Home</RouterLink>
<RouterLink to="/about">About</RouterLink>
<hr/>
<!-- 被路由的组件 会显示在 RouterView -->
<RouterView></RouterView>
路由的模式
1.history (createWebHistory) URL地址更加美观 不带# 更加接近传统的URL。
后期上线后 需要后台配合处理路径问题 否则 刷新可能会有404错误
2.createWebHashHistory 兼容性更好,后期不需要后台的处理
to属性 的两种写法
to 字符串写法
<RouterLink to="/home">Home</RouterLink>
to对象写法
嵌套路由
router/index.ts
import {createRouter, createWebHashHistory, createWebHistory} from 'vue-router'
//被路由的组件
import Home from "@/components/Home.vue";
import About from "@/components/About.vue";
import News from "@/components/News.vue";
import Detail from "@/components/Detail.vue";
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: "/",
component: Home
},
{
path: '/home',
component: Home,
children: [ 嵌套路由
{
path: "news", 路径前不加/
component: News,
children: [
{
path: "detail",
component: Detail
}
]
}
]
},
{
path: '/about',
component: About
}
]
})
export default router;
使用
news.vue
<!-- 导航-->
to:需要写全路径
<RouterLink to="/home/news/detail">Detail</RouterLink>
<!-- 展示被路由的组件-->
<RouterView></RouterView>
命名路由
在路由配置文件 新增属性(name)
{
path: "news",
component: News,
children: [
{
path: "detail",
name:'xq',
component: Detail
}
]
}
使用
<!-- 使用命名路由 需要对象写法的to属性 -->
<RouterLink :to="{
name:'xq'
}">Detail
</RouterLink>
路由懒加载
import {createRouter, createWebHashHistory, createWebHistory} from 'vue-router'
// //被路由的组件
// import Home from "@/components/Home.vue";
// import About from "@/components/About.vue";
// import News from "@/components/News.vue";
// import Detail from "@/components/Detail.vue";
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: "/",
component: () => import('@/components/Home.vue')
},
{
path: '/home',
component: () => import('@/components/Home.vue'),
children: [
{
path: "news",
component: () => import('@/components/News.vue'),
children: [
{
path: "detail",
name: 'xq',
component: () => import('@/components/Detail.vue')
}
]
}
]
},
{
path: '/about',
component: () => import('@/components/About.vue')
}
]
})
export default router;
路由重定向
{
path: "/",
component: () => import('@/components/Home.vue'),
redirect: to => {
// 方法接收目标路由作为参数
// return 重定向的字符串路径/路径对象
return {
// path:"/home/news/detail"
name:'xq' //命名路由
}
}
},
{
path: "/",
component: () => import('@/components/Home.vue'),
redirect: { // path:"/home/news/detail"
name:'xq' //命名路由
}
},
路由传参
1.query传参
<RouterLink to="/home/news/detail?id=1&title=测试数据A">Detail</RouterLink>
<!-- <RouterLink :to="{name:'xq',query:{id:2,title:'测试数据B'}}">-->
<!-- Detail-->
<!-- </RouterLink>-->
接收
import {useRoute} from "vue-router";
const route = useRoute();
{{route.query.参数名}}-{{route.query.title}}2.
2.params传参
1.index.ts中 路由配置占位符
{
path: "news",
component: () => import('@/components/News.vue'),
children: [
{
path: "detail/:id/:title", 占位符
name: 'xq',
component: () => import('@/components/Detail.vue')
}
]
}
使用
<!--params 传参 字符串写法-->
<RouterLink to="/home/news/detail/1/测试数据A">Detail</RouterLink>
<!-- params 传参 使用命名路由 需要对象写法的to属性 -->
<RouterLink :to="{name:'xq',params:{id:2,title:'测试数据B'}}">
Detail
</RouterLink>
接收
import {useRoute} from "vue-router";
const route = useRoute();
接收属性
route.params.属性名
简化接收参数的方式 路由的props
ruter/index.ts
path: "detail/:id/:title",
name: 'xq',
component: () => import('@/components/Detail.vue'),
props:{id:'0000',title:'暂无数据'} // 固定值
//props 布尔写法 将收到的params参数作为 props传入组件
props:true
props 函数写法
props(route) {
return route.query;
}
replace属性
作用:控制路由跳转是 浏览器的历史记录
push 默认值 : 追加历史记录
replace 替换当前记录
编程式路由
import router from "@/router";
// router.replace({
router.push({
// path:''
name: 'xq',
params: {
id: id,
title: title
}
})