vue3(三)

1、父子路由在页面局部跳转的应用
2、通过replace实现不可后退跳转
3、通过钩子函数实现路由和页面跳转
4、路由重定向
5、pinia
6、修改通过useStore拿到的数据
7、storeToRefs
8、pinia里的getters的使用
9、store的组合式写法

1、父子路由在页面局部跳转的应用
假设有一页面NewsView.vue,里面的内容要如何实现如下图所示的布局,如何实现点击页面左半部分文字,而只有页面右半部分的内容发生变化呢?

不难想到,导航栏的内容是挂载到App.vue文件上的。稍加思索的是,要利用RouterView技术,将页面右(Detail.vue文件)挂载到页面左(NewsView.vue文件)上面,Detail.vue要获取到NewsView.vue的内容(参数)。顺便说一下,这里传递参数用的是query,还有一种传参是通过params传参,此处不细展开。具体代码实现如下,请耐心看完:

//  路由配置文件
import { createRouter, createWebHistory} from 'vue-router';
import HomeView from '../views/HomeView.vue';
import AboutView from '../views/AboutView.vue';
import NewsView from '../views/NewsView.vue';
import Detail from '../views/Detail.vue';

const router = createRouter({
    history: createWebHistory(),    //  路由器的工作模式
    routes: [   //  路由规则
        {
            path: '/home',
            name: 'home',
            component: HomeView,
        },
        {
            path: '/about',
            name: 'about',
            component: AboutView
        },
        {
            path: '/news',
            name: 'news',
            component: NewsView,
            children: [
                {
                    path: 'detail',
                    name: 'detail',
                    component: Detail,
                },
            ]
        }
    ]
})
export default router
//  文件App.vue
<template>
  <div class="navigate">
    <RouterLink class="rlink" to="/home">点击此处回主页</RouterLink>
    <RouterLink class="rlink" to="/about">点击此处显示关于</RouterLink>
    <RouterLink class="rlink" to="/news">点击此处显新闻</RouterLink>
    <!-- 普通标签写herf,RouterLink标签写to,或者 :to="{name:""}" -->
  </div>
  <router-view/>    <!-- 挂载路由 -->
</template>

<script lang = "ts">
import { RouterView, RouterLink } from 'vue-router'
export default{
}
</script>

<style scoped>
div.navigate{
  margin: 90px;
}
.rlink{
  margin-right: 40px;
}
</style>
//  文件NewsView.vue
<template>
  <div class = "layout1">  <!-- layout1是flex布局 -->
    <div class="my">
      <div class v-for="i in newslist" :key="i.id">
      <!-- <RouterLink :to="`/news/detail?id=${i.id}&title=${i.title}`">{{ i.title }}</RouterLink> -->
      <RouterLink
        :to="{
            path: '/news/detail',
            query:{
              id: i.id,
              title: i.title,
              content: i.content
            }
        }">   {{ i.title }} 
      </RouterLink>
      </div>
    </div>
    <div class="my">
      <RouterView />  <!-- 挂载路由实现本页面的局部跳转 -->
    </div>
  </div>
</template>

<script lang = 'ts'>
import { reactive } from 'vue'

export default{
  name: "NewsView",
  setup(){
    const newslist = reactive([
      { id: 0, title: "2024年上半年软考报名时间", content: "2024-03-01" },
      { id: 1, title: "2024年上半年软考考试时间", content: "2024-05-25"},
      { id: 2, title: "2024年上半年软考成绩查询时间", content: "2024-08-01" },
    ]);
    return {
      newslist,
    }
  }
}
</script>

<style scoped>
div.my{
  margin-right: 20px;
}
section.layout1 {
  display: flex;
  gap: 22px;
  justify-content: center;
  align-items: center;
}
</style>
//  文件Detail.vue
<template>
    <div>
        <li>编号: {{ route.query.id }}</li>        <!--通过query传递参数-->
        <li>标题: {{ route.query.title }}</li>
        <li>内容: {{ route.query.content }}</li>
    </div>
</template>

<script lang="ts">
import { useRoute } from 'vue-router';

export default{
    name: "Detail",
    setup(){
        let route = useRoute();
        return{
            route
        }
    },
    components:{
    }
}
</script>

2、通过replace实现不可后退跳转
只需在RouterLink上加上replace关键字即可

<RouterLink replace class="rlink" to="/home">点击此处回主页</RouterLink>
<RouterLink replace class="rlink" to="/about">点击此处显示关于</RouterLink>
<RouterLink replace class="rlink" to="/news">点击此处显新闻</RouterLink>

3、通过钩子函数实现路由和页面跳转
在上述News.vue文件中改写成以下代码:

 <script lang = 'ts'>
import { reactive } from 'vue';
import { useRouter } from 'vue-router';
import { onMounted } from 'vue';

export default{
  name: "NewsView",
  setup(){
    const newslist = reactive([
      { id: 0, title: "2024年上半年软考报名时间", content: "2024-03-01" },
      { id: 1, title: "2024年上半年软考考试时间", content: "2024-05-25"},
      { id: 2, title: "2024年上半年软考成绩查询时间", content: "2024-08-01" },
    ]);

    const router = useRouter();

    onMounted(()=>{
      setTimeout(()=>{
        router.push(//可以写纯路径,也可写对象
          {
            name: "detail",
            query: {
              id: "xx",
              title: "xx",
              content: "xx"
            }
          }
        );
      },3000)
    })

    return {
      newslist,
    }
  }
}
</script>

4、路由重定向

{
    path: '/',
    redirect: '/home'
},

5、pinia
集中式状态(数据管理):redux vuex pinia
简单理解:几十甚至上百组件的管理,包括数据传递等
介绍要用到的几个接口:
npm i nanoid:作用返回一个id,这个id唯一
npm i pinia
引入接口后,main.ts需手动修改:

import { createPinia } from 'pinia'

const pinia = createPinia();
app.use(pinia);

接下来需要在src下创建store文件夹,
store中写文件,文件中存储你要用到的所有数据,以count为例子:

//文件 count.ts
import { defineStore } from 'pinia';  //  首先要导入pinia

export const useCountStore = defineStore('count', {  // 这是官方推荐的命名规范!
    state(){    //  存储数据的地方
        return {
            sum:6
        }
    actions: {  //  里面放置的是一个一个的动作方法,用于响应组件的动作
    },
    getters:{
    }
  }
});

接下来,要在addNumber.vue中用到数据sum

<template>
    <div class="count">
        <div>当前求和为 {{ sum }}</div>
        <select v-model="n">
            <option :value="1">1</option>
            <option :value="2">2</option>
            <option :value="3">3</option>
        </select>
        <button @click="addSum">按下加</button>
        <button @click="subSum">按下减</button>
    </div>
</template>

<script lang="ts">
import { ref } from 'vue'
import { useCountStore } from '../store/count';  //  第一步导入对应的store
export default{
    name: "addNumber",
    setup(){
        const countStore = useCountStore();  //  第二步,使用你导入的这个store
        let sum = ref(countStore.sum);      //  第三步,取出数据,接下来照常使用
        let n = ref(1)
        function addSum(){
            sum.value = sum.value + n.value;
        }
        function subSum(){
            sum.value = sum.value- n.value;
        }
        return {
            sum,
            n,
            addSum,
            subSum
        }
    },
    components:{
    }
}
</script>

<style>
div.count{
    margin: 20px;
    padding: 10px;
    background-color: skyblue;
    border-radius: 10px;
    box-shadow: 0 0 5px;
}
select,button{
    margin: 0 5px;
    height: 25;
}
</style>

再举一个例子:

//  文件talk.ts
import { defineStore } from 'pinia'
import { reactive } from 'vue';
export const useTalkStore = defineStore('talk', {
    state() {
        return {
            talklist: reactive([
                {id: 'ftrfasdf01', title: '这是第一句话'},
                {id: 'ftrfasdf02', title: '这是第二句话'},
                {id: 'ftrfasdf03', title: '这是第三句话'},
            ]),
        }
    }
});
//  LoveTalk.vue
<template>
    <div class = count>
        <button @click="getLoveTalk">点击此处获取一句话</button>
        <ul v-for="i in talklist" :key="i.id">
            <li>{{ i.title }}</li>
        </ul>
    </div>
</template>

<script lang="ts">
import { reactive } from 'vue';
import { nanoid } from 'nanoid';
import axios from 'axios';
import { useTalkStore } from '@/store/talk';

export default{
    name: "LoveTalk",
    setup(){
        const talkStore = useTalkStore();
        let talklist = reactive(talkStore.talklist);
        async function getLoveTalk(){
            let result = await axios.get("https://api.uomg.com/api/rand.qinghua?format=json");
            let obj = { id: nanoid(), title: result.data.content };
            talklist.unshift(obj);  //  后出现的在上面
        }
        return {
            talklist,
            getLoveTalk
        }
    },
    components:{
    }
}
</script>

<style>
</style>

6、修改通过useStore拿到的数据
第一种修改方式,拿到countStore后直接修改

        const countStore = useCountStore();
        let n = ref(1)  //用户选择的数字
        function addSum(){
            countStore.sum = countStore.sum + n.value;
        }
        function subSum(){
            countStore.sum = countStore.sum - n.value;
        }

第二种修改方式,通过$patch

countStore.$patch({sum: 10});

第三种修改方式,通过action

//  文件count.ts
import { defineStore } from 'pinia';

export const useCountStore = defineStore('count', {
    state(){
        return {
            sum:0
        }
    },
    actions: {  //里面放置的是一个一个的动作方法,用于响应组件的动作
        add(value:number){  //  变量value是number类型
            this.sum = this.sum + number;
        },
        sub(value:number){
            this.sum = this.sum - number;
        }
    }
});
//  文件addCount.vue,使用该数据的局部代码
    function subSum(){
        countStore.sub(n.value);
    }

7、storeToRefs
storeToRefs只会关注store里的数据,不会关注里面的方法进行ref包裹

const personStore = usePersonStore()
const { id, name, address } = storeToRefs(personStore);
//  如果这里用的是toRefs,那么会将很多没用的数据解构出来

8、pinia里的getters的使用
Getters相当于Store的计算属性:
可以用defineStore()中的getters属性定义
getters中可以定义接受一个state作为参数的函数

//  文件src/store/count.ts
import { defineStore } from 'pinia';

export const useCountStore = defineStore('count', {
    state(){    //  存储数据的地方
        return {
            sum:0
        }
    },
    actions: {  //  里面放置的是一个一个的动作方法,用于响应组件的动作
        add(value:number){  //  变量value是number类型
            this.sum = this.sum + value;
        },
        sub(value:number){
            this.sum = this.sum - value;
            console.log(this)
        }
    },
    getters:{
//        bigSum(state){  //  对数据不满意之后,加工的地方
//            return state.sum * 100;
//        },

        //  或者你可以这样写:
        bigSum():number{    //  告诉系统你返回值是number类型
            return this.sum * 100;
        }

        //  官方鼓励这样写:bigSum:(state)=>{ state.sum*100 }
    }
});

9、store的组合式写法

//  文件src/store/count.ts
import { defineStore } from 'pinia';
import { ref } from 'vue'

export const useCountStore = defineStore('count', ()=>{  //  接下来的内容当setup用
        let sum = ref(99)
        function add(value:number){
            sum.value = sum.value + value;
        }
        function sub(value:number){
            sum.value = sum.value - value;
        }
        return{
            sum,
            add,
            sub
        }
    },
)
posted @ 2024-01-05 00:23  惊朝  阅读(5)  评论(0编辑  收藏  举报