自定义hooks
准备工作:首先导入axios的依赖
案例
首先写一个子组件,如下
html
<template>
<h2>{{ sum }}</h2>
<button @click="addSum">点我sum+1</button>
<hr>
<img v-for="(dog,index) in dogs" :key="index" :src="dog.src">
<br>
<button @click="addDog">点我狗狗+1</button>
</template>
<script lang="ts" setup>
import axios from 'axios';
import { ref,reactive } from 'vue';
let sum=ref(0)
let dogs=reactive([{src:"https://images.dog.ceo/breeds/pembroke/n02113023_6826.jpg"}])
function addSum(){
sum.value++;
}
function addDog(){
axios.get('https://dog.ceo/api/breed/pembroke/images/random').then(
response=>{
let msg={src:response.data.message}
console.log(msg)
dogs.push(msg)
}
).catch(error=>{
console.log(error,"找不到路径")
}
)
}
</script>
<style>
img{
height: 100px;
margin-left: 5px;
}
</style>
这个组件实现的效果如下(有两个功能,点击按钮sum+1 点击按钮出现一张新的狗狗的图片)
注意观察代码的结构,如果一个组件要实现的功能多起来时,方法和数据都放在一个vue里面,会导致代码特别臃肿,要同时找到一个方法所需要的数据和方法也十分困难,这时候hook就派上用场了。
什么是hook?hook有什么优势?
-
什么是
hook
?------ 本质是一个函数,把setup
函数中使用的Composition API
进行了封装,类似于vue2.x
中的mixin
。 -
自定义
hook
的优势:复用代码, 让setup
中的逻辑更清楚易懂。
用自定义hook对上述代码进行改进
1.首先在src目录下新建一个hooks目录
2.编写自定义hook(按功能分类,将一个功能的方法和数据抽离出来,用函数包裹,最后把需要暴露的数据和方法交出去)
注意hook的命名规范为: useXxxxx
useSum.ts
useDog.ts
3.在vue中调用hook
html
<template>
<h2>{{ sum }}</h2>
<button @click="addSum">点我sum+1</button>
<hr>
<img v-for="(dog,index) in dogs" :key="index" :src="dog.src">
<br>
<button @click="addDog">点我狗狗+1</button>
</template>
<script lang="ts" setup>
/* 引入 */
import useSum from '../hooks/useSum';
import useDog from '../hooks/useDog';
/* 调用 */
let {sum,addSum}=useSum()
let {dogs,addDog}=useDog()
</script>
<style>
img{
height: 100px;
margin-left: 5px;
}
</style>
十分清爽,这里体现了vue3组合式api的思想
Vue中的路由
用路由器实现一个基本的切换效果
首先先安装路由器依赖
1.在src文件夹中创建一个router文件夹
2.准备好需要的vue们
这里准备了一个Main.vue作为主界面,要在这里面切换Community,Friend,Home三个组件
2.写一个router
MyRouter.ts
TypeScript
import { createRouter,createWebHistory } from "vue-router";
import community from "../components/Community.vue";
import friend from "../components/Friend.vue";
import home from "../components/Home.vue";
const router=createRouter({
history:createWebHistory(),
routes:[
{
path:"/community",
component:community
},
{
path:"/friend",
component:friend
},
{
path:"/home",
component:home
}
]
})
3.在main.ts里面注册这个router
TypeScript
import { createApp } from "vue";
import App from "./App.vue";
//引入路由器
import router from "./router/MyRouter";
const app=createApp(App)
app.use(router)//注册路由器
app.mount('#app')
4.在主界面上用RouteLink组件绑定对路由路径的响应
Main.vue
html
<!-- 登录成功后的主界面 -->
<template>
<h2>登录成功后的主界面</h2>
<div class="app">
<!-- 导航区 -->
<div class="navigate">
<RouterLink to="/community" active-class="active" class="navi-style">社区</RouterLink>
<RouterLink to="/friend" active-class="active" class="navi-style">交友</RouterLink>
<RouterLink to="/home" active-class="active" class="navi-style">个人中心</RouterLink>
</div>
<!-- 展示区 -->
<div class="main-content">
<RouterView></RouterView>
</div>
</div>
</template>
<script lang="ts" setup>
import {RouterLink,RouterView} from 'vue-router'
</script>
<style>
.active{
color: red;
}
.navi-style{
margin-left: 10px;
}
</style>
Community.vue(其他两个结构同这个一样)
html
<!-- 社区模块 -->
<template>
<h2>社区模块</h2>
</template>
<script lang="ts" setup>
</script>
<style>
</style>
效果
两个注意点
路由组件通常存放在pages
或 views
文件夹,一般组件通常存放在components
文件夹。(ps:路由组件就是通过路由器才能被渲染的组件,也就是写在RouterLink里面的组件)
通过点击导航,视觉效果上"消失" 了的路由组件,默认是被卸载 掉的,需要的时候再去挂载。
路由器工作模式
history模式
hash模式
怎么写要跳转的路由(三种方法)
to的两种写法
html
<!-- 第一种:to的字符串写法 -->
<router-link active-class="active" to="/home">主页</router-link>
<!-- 第二种:to的对象写法 -->
<router-link active-class="active" :to="{path:'/home'}">Home</router-link>
命名路由(后面可以用来简化路由跳转和传参的问题)
在路由器中给路由规则命名
在Main.vue中这样写
可以看到第一种是to的字符串写法,后面两种是to的对象写法
html
<!-- <RouterLink to="/community" active-class="active" class="navi-style">社区</RouterLink> -->
<!-- 里面只能用单引号 -->
<!-- <RouterLink :to="{path:'/community'}" active-class="active" class="navi-style">社区</RouterLink> -->
<RouterLink :to="{name:'shequ'}" active-class="active" class="navi-style">社区</RouterLink>
嵌套路由
要实现的效果:点击社区模块显示所有的帖子,点击帖子标题在下方显示帖子的详情
1.编写Post.vue
2.将Post.vue 配置成Community.vue的子路由
TypeScript
const router=createRouter({
history:createWebHistory(),
routes:[
{
path:"/community",
name:"shequ",
component:community,
//配置子路由
children:[
{
path:"post",
name:"tiezi",
component:post
}
]
},
{
path:"/friend",
component:friend
},
{
path:"/home",
component:home
}
]
})
export default router
3.在Community中写跳转
前两种都要加完整路径
html
<!-- 社区模块 -->
<template>
<h2>社区模块</h2>
<li v-for="post in postList" :key="post.postId">
<!-- <RouterLink to="/community/post">{{ post.title }}</RouterLink> -->
<!-- <RouterLink :to="{path:'/community/post'}">{{ post.title }}</RouterLink> -->
<RouterLink :to="{name:'tiezi'}">{{ post.title }}</RouterLink>
</li>
<router-view></router-view>
</template>
<script lang="ts" setup>
import { onMounted,onUnmounted } from 'vue';
let postList=[
{postId:"1",title:"今天天气真好",content:"我想出去玩"},
{postId:"2",title:"最近有电影好看?",content:"推荐一下"},
{postId:"3",title:"再也不万元神了",content:"是不可能的"},
{postId:"4",title:"一眼顶针",content:"鉴定为假"},
{postId:"5",title:"哈哈哈哈",content:"1234889"}
]
//切换到这里挂载,切换到别的view被卸载
onMounted(()=>{
console.log("community被挂载了")
})
onUnmounted(()=>{
console.log("community被卸载了")
})
</script>
路由传参
query参数传递
传递参数
html
<!-- 传死数据 -->
<!-- <RouterLink to="/community/post?postId=1&title=去干嘛&content=114514">{{ post.title }}</RouterLink> -->
<!-- 模板字符串嵌入js -->
<!-- <RouterLink :to="`/community/post?postId=${post.postId}&title=${post.title}&content=${post.content}`">{{ post.title }}</RouterLink> -->
<!-- 携带query参数 -->
<RouterLink :to="
{
path:'/community/post',
query:
{
postId:post.postId,
title:post.title,
content:post.content
}
}
">{{ post.title }}</RouterLink>
接收参数
html
<template>
<div class="post-content">
<ul>
<li>id: {{route.query.postId }}</li>
<li>标题: {{ route.query.title }}</li>
<li>内容: {{ route.query.content }}</li>
</ul>
</div>
</template>
<script lang="ts" setup>
//注意是useRoute 不是useRouter
import { useRoute } from 'vue-router';
const route=useRoute()
</script>
param参数传递
传递参数
首先需要在路由规则里面添加占位
TypeScript
//param参数占位版
children:[
{
path:"post/:postId/:title/:content?", //content加个?表示可选
name:"tiezi",
component:post
}
]
html
<!-- 传死数据 -->
<!-- <RouterLink to="/community/post/1/出去玩/谁一起">{{ post.title }}</RouterLink> -->
<!-- content是可选的 -->
<!-- <RouterLink to="/community/post/1/出去玩">{{ post.title }}</RouterLink> -->
<!-- 模板字符串嵌入js -->
<!-- <RouterLink :to="`/community/post/${post.postId}/${post.title}/${post.content}`">{{ post.title }}</RouterLink> -->
<!-- 携带param参数 用param传递参数时,必须使用 name -->
<RouterLink :to="
{
name:'tiezi', //养成习惯,用单引号
params:{
postId:post.postId,
title:post.title,
content:post.content
}
}
">{{ post.title }}</RouterLink>
接收参数
html
<template>
<div class="post-content">
<ul>
<li>id: {{route.params.postId }}</li>
<li>标题: {{ route.params.title }}</li>
<li>内容: {{ route.params.content }}</li>
</ul>
</div>
</template>
<script lang="ts" setup>
//注意是useRoute 不是useRouter
import { useRoute } from 'vue-router';
const route=useRoute()
</script>
路由的props配置
作用:用于简化接收数据的写法
1.param
2.query (当然param也可以这么写)
replace属性
-
作用:控制路由跳转时操作浏览器历史记录的模式。
-
浏览器的历史记录有两种写入方式:分别为
push
和replace
:push
是追加历史记录(默认值)。replace
是替换当前记录。
在默认的push模式下,可以点击按钮回滚
开启replace
回滚不了了
路由:编程式路由导航
我们前面写的代码,只能通过<RouterLink>标签实现路由跳转,假设我们要实现一个登录功能,会发现我们根本实现不了这个功能,因为<RouterLink>是个标签,不能放在函数里,而我们进行逻辑判断肯定要用到方法。
一个小案例
用button实现和下面<RouteLink>一样的效果
html
<button @click="showPost(post)">使用编程式导航来跳转路由,显示帖子内容</button>
<RouterLink :to="
{
path:'/community/post',
query:
{
postId:post.postId,
title:post.title,
content:post.content
}
}
">{{ post.title }}</RouterLink>
1.拿到路由器对象
html
import { useRouter } from 'vue-router';
const router=useRouter()
2.要跳到哪里,传什么参数(原来 :to 里面怎么写,这个里面就怎么写)
html
function showPost(post:any){
router.push( {
path:'/community/post',
query:
{
postId:post.postId,
title:post.title,
content:post.content
}
})
}
选择router.push 或router.replace 决定是否能回溯
测试:点击按钮一样能实现之前的效果
路由:重定向
作用:将特定的路径,重新定向到已有路由。
案例:
需求:刚进来啥也没有,我想要刚进来就显示社区的内容
**************************************
在路由器中定义一条新路由, 这条路由会在访问
的时候重定向路由到
这样,我们一登录成功就能看到社区的帖子了