1 Star 1 Fork 0

飘尘 / 我的博客(前端vueJS)

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
配置此项目的步骤(当作复习).md 29.94 KB
一键复制 编辑 原始数据 按行查看 历史
飘尘 提交于 2023-07-20 12:45 . 对接完成,等待部署

配置此项目的步骤(当作复习)

1. 配置路由以及axios

首先,需要进行npm i vue-router@3(vue2项目的话,vue3使用4版本)。然后在src下创建view文件夹,用于存放路由页面。然后src下创建router文件夹,里面给上一个index.js和routes.js文件。文件内容如下:

//index.js 用于配追路由配置以及浏览器的历史模式等 这里是最重要的地方
import { createRouter, createWebHistory } from "vue-router";
import routes from "./routes";

const router = createRouter({
  history: createWebHistory(),
  routes
});

export default router;
//routes.js 其实可以与index.js合写在一起,分开写方便些 这里编辑的是router中的路由列表 从上向下匹配
const routes = [
  {
    path: "/",
    redirect: "/login"
  },
  {
    name: "index",
    path: "/index",
    component: () => import("@/view/index"),
    meta: {title: "主页"},
    children: []//子路由 里面写的和外面一样 注意路径不用加上外面的 自己是自己的就行
  },
  {
    name: "login",
    path: "/login",
    meta: {title: "登入"},
    component : () => import("@/view/login")
  },
    {
    name: "404",
    path: "/404",
    meta: {title: "页面不见了"},
    component: () => import("@/view/404")
  },
  //写在最底部,实现找不到路径跳转到404页面
  {
    path: '/:pathMatch(.*)',
    redirect: '/404'
  }
];

export default routes;

同时还需要在main.js中进行配置:

import { createApp } from 'vue'
import App from './App.vue'
// 引入路由
import router from './router';

createApp(App).use(router).mount('#app');//注意use要在mount之前

然后添加router-view标签作为路由组件的渲染容器。一般直接放在app里。 对App.vue做如下的修改:

<template>
  <router-view></router-view>
</template>

<script>

export default {
  name: 'App',
  components: {
  }
}
</script>

<style>

</style>

然后是跳转到指定路由,使用router-link标签或者是this.$router.push("路径名字")这个方法。

然后配置404页面:

配置路由守卫:在index.js里,在router对象身上。注意三个参数的顺序。https://blog.csdn.net/qq_54334713/article/details/126721576 前置后置组件内独享(在routes中配置)。

//配置白名单,名单中的路径无需守卫
const whiteRouter = ["/login", "/404"];

//配置前置路由守卫
router.beforeEach((to, from, next)=>{
  if(whiteRouter.indexOf(to.path) == -1){//要去的不是白名单中的路由 需要鉴权
    let token = localStorage.getItem("token");
    if(token){
      next();
    }else{
      next("/login");
    }
  }else{
    next();
  }
});

//后置路由守卫实现标题切换 
router.afterEach((to) => { 
  document.title = to.meta.title
});

同样的,配置路由可以分文件写,然后在index.js中进行最后的合并即可:

// src/router/home.js
import Home from '@/views/Home.vue';

const homeRoutes = [
  {
    path: '/',
    name: 'Home',
    component: Home,
  },
];

export default homeRoutes;

// src/router/about.js
import About from '@/views/About.vue';

const aboutRoutes = [
  {
    path: '/about',
    name: 'About',
    component: About,
  },
];

export default aboutRoutes;

// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import homeRoutes from './home';
import aboutRoutes from './about';

const routes = [...homeRoutes, ...aboutRoutes];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

至于axios:

http://www.manongjc.com/detail/40-krlbbynxscdwfpu.html

处理跨域(必须):https://blog.csdn.net/XSL_HR/article/details/127813674

整体而言,是:

  1. 配置axios,安装之后,在src下新建config.js,书写如下内容配置axios:

    import axios from "axios";
    // import store from "@/store";
    
    // 创建并配置一个新的axios
    const service = axios.create({
        // baseURL: process.env.VUE_APP_BASE_API, // 这里指所有接口请求的“请求地址前缀”,完整请求地址 = 请求地址前缀 + 接口后缀,即 url = baseURL + request url
        timeout: 60000, // 请求超时时间 毫秒
         withCredentials: true,   // 异步请求时是否携带cookie 需要配置这里,因为虽然浏览器发送请求的时候是自动携带cookie的,但是使用js发送的请求为了防止跨站请求伪造(CSRF)攻击,需要自己设定好这里
        // headers: {   // 设置后端需要的传参类型,后端不要求,这没必要设置
        //     "Content-Type": "application/json",
        //     token: "your token",
        //     "X-Requested-With": "XMLHttpRequest",
        // },
    });
    
    // 添加请求拦截器
    service.interceptors.request.use(
        (config) => {
            // 在发送请求之前做些什么。。。
            // 比如配置请求token(如果需要的话)
            // const tokenInfo = store.state.account.tokenInfo;
            // if (tokenInfo && tokenInfo.tokenName) {
            //     config.headers[tokenInfo.tokenName] = tokenInfo.tokenValue; //配置请求token
            // }
            return config;
        },
        (error) => {
            // 对请求错误做些什么
            return Promise.reject(error);
        }
    );
    
    // 添加响应拦截器
    service.interceptors.response.use(
        (response) => {
            const res = response.data;
            if (res.code == 401) {
                //登录拦截:接口需要登录,但用户未登录
                // store.commit("account/setUserInfo", ""); //移除用户信息
                // if(confirm("登录失效,是否重新登录")){
                //     console.log("确定")
                // }else{
                //     console.log("取消")
                // }
                return Promise.reject(new Error(res.msg || "Error"));
            } else {
                //其他情况则返回结果,对应状态code需在具体请求函数里判断
                return res;
            }
        },
        (error) => {
            alert(error.msg || "服务器开小差了呢,请稍后再试~");
            return Promise.reject(error);
        }
    );
    
    export default service;
  2. 然后新建src下新建api文件夹,里面书写相关的网络请求函数,例如:

    import request from "../config/request";
    
    export function nomalNews() { //当然,如果是post,应该添加参数形参啥的
      return request({
          url: "/api/toutiao/index?type=top&key=3dc86b09a2ee2477a5baa80ee70fcdf5", //注意请求路径不要写全的 写成这样即可
          method: "get",
      });
    }
    
    export function getNews(params) { //get用参数params
      return request({
          url: "/api/toutiao/index?type=top&key=3dc86b09a2ee2477a5baa80ee70fcdf5", //注意请求路径不要写全的 写成这样即可
          method: "get",
          params
      });
    }
    
    export function postNews(data) { //post用参数data
      return request({
          url: "/api/toutiao/index?type=top&key=3dc86b09a2ee2477a5baa80ee70fcdf5", //注意请求路径不要写全的 写成这样即可
          method: "post",
          data
      });
    }
  3. 然后组件中导入调用即可:import{ getNews }from '@/API/getNews'; 这里注意导入方式 默认暴露与分别暴露的区别

  4. 记得配置跨域,在vue.config.js中书写如下内容:

    const { defineConfig } = require('@vue/cli-service')
    module.exports = defineConfig({
      transpileDependencies: true,
      devServer: {
      //   host: 'localhost',
      //   port: "8080",
      //   open: true,
        proxy: {
          '^/api': {
              target: 'http://localhost:3000/',//接口的前缀(后端地址)
              // ws: true,//代理websocked
              changeOrigin: true,//虚拟的站点需要更管origin
              pathRewrite:{
                  '^/api':''//重写路径
              }
          }
        }
      }
    })

对于出现的异步回调导致使用数组赋值拿到响应数据出现cannot set property "xx" of undefined的问题,我的评价是:

//不使用下面的方式 下面的方式会报错
this.responseData.forEach((item, index)=>{
    this.tableArr[index].name = item.name;
    this.tableArr[index].age = item.age;
});

//而是使用这种方式
//首先,前提是为了避免问题,将responseData和tableArr都用ref([])来一下
this.responseData.forEach((item, index)=>{
    this.tableArr[index] = {name: item.name, age: item.age};
});// 将改值变为赋值即可

多个router-view情况,跳转路径需要选定一个展示:修改为:

<router-view name="xxx"> </router-view>
<router-view name="aaa"> </router-view>

//然后在routes.js中 指定对应的router-view的名字即可
{
    name: "index",
    path: "/index",
    components: {xxx: () => import("@/views/index")}, // 注意这里是components 不是component了
    meta: {title: "主页"},
    children: []//子路由 里面写的和外面一样 注意路径不用加上外面的 自己是自己的就行
  },
  {
    name: "login",
    path: "/login",
    meta: {title: "登录"},
    components : {aaa: () => import("@/views/login")} 
  },

但是上面的不是管理系统中导航跳转 卡片中的页面改变的效果,那种效果只需要在对应位置加一个新的router-view,然后将对应的路由规则写到父级的children中即可!无需像上面一样那么做!

实现面包屑:https://blog.csdn.net/woodwhale/article/details/123944372

2. 一些CSS属性

导入全局样式: 非常简单,只需要在main.js中去import "./assets/main.css";即可,别的啥也不用动了。

配置渐变色:https://blog.csdn.net/m0_64231944/article/details/127706916

/*使用下列属性*/
body{
    background-image: linear-gradient(right to bottom, color1, color2);
}

text-ident:设置文本的首行缩进,在input里设置的可能多一些,设置占位文本的缩进。

inset:https://blog.csdn.net/u011781521/article/details/125253075 用作定位元素位置的left right bottom top的简写 对应顺序为top: 0; right: 0; bottom: 0; left: 0; inset:0;即为此top: 0; right: 0; bottom: 0; left: 0;

v-bind单项绑定 v-model双向绑定

配置element-ui:vue3不能用element-ui(vue2专属),只能用element-plus,首先是使用npm install element-plus --save指令安装。然后在main.js中加上以下句子:

import ElementPlus from 'element-plus';
import 'element-plus/theme-chalk/index.css';

import locale from 'element-plus/lib/locale/lang/zh-cn';

createApp(App).use(ElementPlus, { locale }).mount("#app");//一定要在挂载之前进行使用

新版使用与原来不太一样了。新版的引入有点繁琐?还是我之前的引入不会写了。

vue3的相关属性的使用:

vue3 watch:要监视属性名(不要this):{handler(newValue,oldValue){ }} 当被监视的变量的值发生变化的时候,就会调用handler函数。

vue3 computed:data里不用写这个变量的名字,只在computed写即可,用的时候一样用。然后还有就是必须要有返回值。直接写成属性名:function(){}的形式来处理,这个函数就会被直接当成getter。完全体:name:{get(){return xxx},set(){xxxx}} 简写:name:function(){return xxxx} 即可。

router-link在css里当成a标签去使用选择器即可。不要用router-link,会导致选择不到的。router-link一定要带着to属性,哪怕填空字符串,也是一定要有的!

使用伪元素一定要加的是content和display:block啥的!不加没有效果的

想要让一个盒子具有当内容少的时候,维持固定高度,当内容较多的时候,根据内容多少自动调节高度这样的功能的话,可以使用min-height来设置,同时,要是文字内容,还需要配合使用overflow-wrap: break-word进行换行。

呃呃呃,别忘了怎么让文本居中:水平居中:使用text-align: center属性,垂直居中,设置行高line-height=容器高度即可,二者配合即可实现文字在容器中垂直与水平居中。

设置盒子背景图(自动填满整个盒子)并且设置为半透明(使用伪类实现):

.bgi{
     background-size:cover;
   	 background-repeat:no-repeat;
	 background-image: url("");
}
上面设置背景图自动填满整个盒子效果

下面使用伪类实现半透明背景图
.bgi::before{
    content: "";
    display: block;
    width: 100%;
    height: 100%;
    background-color: rgba(255, 255, 255, .6); 这里调整透明度 其实这里是越高越不透明 因为是遮罩,不是设置本体的透明度
}

另外,渐变色:https://blog.csdn.net/m0_64231944/article/details/127706916

background: linear-gradient(to right,#333399,#ff00cc);

3. 组件参数传递

vue3兄弟组件间传参:绑定事件总线在vue3中因为Vue.prototype被取消,所以不再被使用了。在Vue3中我们通常会使用mitt库或者vuex作为参数传递的媒介。对于较大型的项目而言,一般使用vuex,但是对于小型项目,一般使用mitt作为媒介。使用方式:首先得安装npm install mitt --save,然后引入,创建eventBus.js文件(文件名自定义即可)https://blog.51cto.com/u_15057841/4748952

import mitt from 'mitt';

const emitter = mitt();
export default emitter;

然后在发送端和接收端都要引入这个函数:

import emitter from "../untils/bus"; //这里的路径是自定义的

发送端再去书写:

// 前面是事件名称,后面是要传入的参数
emitter.emit("response", response);

接收端书写:

// 这样两个组件间就可以进行传值通信了
emitter.on("response", (response) => {
    console.log(response);
});

另外,父子组件传参可以使用组件的props属性相关的内容:https://blog.csdn.net/severestcritic/article/details/121434943

三类:

  1. 父向子传参,最为简单,在书写子组件的时候,<componenetName propName=propValue >,同时在子组件中的props属性要声明对应的prop,然后写明类型啥的。
  2. 子向父传参(常规版):详见文章
  3. 子向父传参(v-model):详见文章

使用this.$router.push({ name: 'ArticlePage'(这里是路由名,不是组件名), params: { id: id } });可以进行路由跳转以及携带参数!携带的参数为路由参数,对应下面的这种路由规则:

import Vue from 'vue';
import Router from 'vue-router';
import ArticlePage from '@/components/ArticlePage';

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/article/:id',
      name: 'ArticlePage',
      component: ArticlePage,
    },
  ],
});

这样子就可以实现类似于正常的博客网站的在连接后面跟数字的博客文章地址的效果了。同样的,需要拿出来,这并不是组件的参数,而是通过路由携带的参数:

data () {
  return {
    articleID: this.$route.params.id,
  }
},

事件发布与订阅:

参考博客:https://zhuanlan.zhihu.com/p/612816926

4. 动态组件

这个知识之前没怎么用过,这里详细讲一下:

我是用动态组件实现了根据路由中的参数:/article/:id这个id参数来渲染不同的页面,这样绕过了路由,并且path就是/article/:id。

在 Vue 中,动态组件允许你动态地切换组件。你可以使用保留的 <component> 元素,然后通过 is 特性来绑定要渲染的组件。

这是一个简单的例子,它展示了如何使用动态组件来切换不同的组件:

<template>
  <div>
    <button @click="currentView = 'view-a'">Show A</button>
    <button @click="currentView = 'view-b'">Show B</button>
    <component :is="currentView"></component>
  </div>
</template>

<script>
import ViewA from './ViewA.vue';
import ViewB from './ViewB.vue';

export default {
  components: {
    ViewA,
    ViewB,
  },
  data() {
    return {
      currentView: 'view-a',
    };
  },
};
</script>

复制

在这个例子中,我们定义了两个按钮,分别用来切换当前要渲染的组件。当用户点击 “Show A” 按钮时,将会展示 ViewA 组件;当用户点击 “Show B” 按钮时,将会展示 ViewB 组件。

动态组件非常强大,它允许你在运行时动态地切换组件。你可以根据应用程序的状态或用户的输入来决定要渲染哪个组件。(其实,真要说起来,就是一个不用路由的路由罢了)

5. 配置Vuex/Pinia

1. vuex(选项式API)

详细见本篇博客:https://blog.csdn.net/w137160164/article/details/131158381

首先安装:npm i vuex

随后需要添加文件夹(src/store),并在这个文件夹下添加index.js,里面书写内容:

import { createStore } from 'vuex'
// 类似 Redux 中的建立状态树

export default createStore({
  
  // 1、 存储所有全局数据
  state: {
    
  },
 
  // 2、 需要通过计算获取state里的内容获取的数据
  // 只能读取不可修改
  getters: {
   
  },
 
  //  3、定义对state的各种操作
  // why不直接实现在mutation里需要写到action里?
  // mtations不能执行异步操作。aq:从云端获取信息-->(等待云端反馈)更新到state异步操作
  // 因此说:对于异步操作需要放到action里,简单的直接赋值操作可以直接放到mutation里
  mutations: {
    updataUser(state,user){
      state.user.username = user.username;
    }
  },

  // 3、定义对state的各种操作
  // actions无法直接修改state,需要在mutations里更新
  // mutation不支持异步,所以需要在action里写api到url
  actions: {
      // 比说action定义了更新state的操作
      // 但是不可对其直接修改
      // 所有的修改操作必须放到mutations里
  },

  // state中信息过长时
  // 用来将state进行分割
  // 如下,将state树分割出一个user state。
//  modules: {
//	user: ModuleUser,
 // }
});

随后,在main.js中进行注册store组件:

import store from './store'
app.use(store) //注册vuex

使用vuex之前,需要了解几个vuex的核心概念:state(仅可用于访问),mutations(仅用于修改state),action(处理复杂逻辑下的state的修改,但是不是直接更改,而是调用mutations进行更改的),getter(store的计算属性)

  1. state:这个是数据源,是全局共同维护的,存储所有的共享对象。

    定义state有两种方式,二选其一即可:

    //对象方式
    state:{ 
      isTabbarShow:true
    },
    //函数方式
    state() {
      return {
        isTabbarShow:true
      }
    },

    访问方式也是两种(因为选项式API和组合式API):

    // 选项式API
    console.log(this.$store.state.isTabbarShow)
    
    // 组合式API
    import { useStore } from 'vuex'
    const store = useStore()
    console.log(store.state.isTabbarShow)
  2. mutations:

    • Mutations 是同步修改 state 状态的。
    • Mutations 修改 state 必须是通过 store.commit() 来触发。
    • Mutations 只能处理同步操作。
      mutations:{
        changeState(state,payload) {
          state.isTabbarShow = payload
        }
      },
    

    使用mutations:

    // 选项式API中
    this.$store.commit('changeState',true) 
    
    // 组合式API中
    import { useStore } from 'vuex'
    const store = useStore()
    store.commit('changeState',true) 
    
  3. action:

    Action 用于处理异步操作或复杂的操作逻辑,类似于 Mutations,但是 Action 支持异步操作,而且一般不直接修改 state 状态,而是提交 Mutations 完成具体的状态变更。

    Action 是异步的,用于处理异步操作或复杂的操作逻辑。 Action 一般不直接修改 state 状态,而是提交 Mutations 完成具体的状态变更。 Action 可以提交 Mutations,也可以赋值 state 状态。 Action 通过 store.dispatch 触发。

    定义action:

      actions:{
        ayncChangeState(context) {
          context.commit('changeState',true); // 通过$store.commit()来进行状态修改,这样子就能做到
        }
      }
    

    使用action:

    // 选项式API
    this.$store.dispatch('ayncChangeState') // 参数名字是action的名字
    
    // 组合式API
    import { useStore } from 'vuex'
    const store = useStore()
    store.dispatch('ayncChangeState') 
    
  4. getter:

    store中的计算属性。

    定义:

    getters: {
      doneTodos: state => {
        return state.todos.filter(todo => todo.done)
      }
    }
    

    使用:

    // 选项式API
    computed: {
      doneTodos() {
        return this.$store.getters.doneTodos
      }
    }
    
    // 组合式API
    store.getters.doneTodos
    

module:如果我们管理的信息太多的时候,可以使用module来将其分割开来,并最终在store的index.js中将其整合起来。(其实就是分文件呗)

在store/module文件夹中:

const user = {
  namespaced: true,
  state: {
    name: 'John Doe',
    age: 30,
    email: 'johndoe@example.com'
  },
  getters: {
    fullName (state) {
      return state.name
    }
  },
  mutations: {
    setName (state, newName) {
      state.name = newName
    }
  },
  actions: {
    updateName ({ commit }, newName) {
      commit('setName', newName)
    }
  }
}
export default user
const books = {
  namespaced: true,
  state: {
    name: 'Vue入门',
    price: 30, 
    author: 'John Doe'
  },
  getters: {
    totalMoney (state) {
      return state.price 
    }
  },
  mutations: {
    setName (state, newName) {
      state.name = newName
    }
  },
  actions: {
    updateName ({ commit }, newName) {
      commit('setName', newName)
    }
  }
}
export default books

在store/index.js中:

import { createStore } from 'vuex'
import userModule from './module/userModule.js'
import bookModule from './module/bookModule.js'
const store = createStore({
  modules:{
    userModule,
    bookModule
  }
})

export default store

使用module:

// 选项式API
this.$store.state.userModule
this.$store.state.bookModule
this.$store.commit("setName", name);

// 组合式API
import { useStore } from 'vuex'
const store = useStore()
const userModuleState = computed(() => store.state.userModule.stateName)
// userModule mutation的使用
const updateName = name => {
  store.commit('userModule/updateName', name) 
}

vuex中的辅助函数:(主要是用于将store中的属性映射到vue组件的计算属性当中)

mapState,mapActions,mapMutation,mapGetters

// 在组件中使用 mapState
import { mapState } from 'vuex'

export default {
  computed: {
    ...mapState({
      count: state => state.count,
      message: state => state.message
    })
  }
}


// 在组件中使用 mapGetters
import { mapGetters } from 'vuex'

export default {
  computed: {
    ...mapGetters({
      doneTodos: 'doneTodos',
      doneTodosCount: 'doneTodosCount'
    })
  }
}


// 在组件中使用 mapMutations
import { mapMutations } from 'vuex'

export default {
  methods: {
    ...mapMutations([
      'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
      'add' // 将 `this.add()` 映射为 `this.$store.commit('add')`
    ])
  }
}


// 在组件中使用 mapActions
import { mapActions } from 'vuex'

export default {
  methods: {
    ...mapActions([
      'incrementAsync', // 将 `this.incrementAsync()` 映射为 `this.$store.dispatch('incrementAsync')`
      'addAsync' // 将 `this.addAsync()` 映射为 `this.$store.dispatch('addAsync')`
    ])
  }
}

这里需要注意的是,当我们使用组合式API时,如在<script setup>语法糖中,我们无法使用上面介绍的辅助函数,因为这些辅助函数的底层是调用的this.$store,而在组合式API中,不存在this,所以上面的几个辅助函数在组合式API中无法使用!

2. Pinia(组合式API)

参考博客:https://blog.csdn.net/w137160164/article/details/131160122

Pinia是新的官方的管理工具。vuex被它给替代掉了。

还是得先安装啊:npm i pinia

安装完成后,在main.js中进行注册。

import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';

const app = createApp(App);

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

app.mount('#app');

他的内容的名字与vuex的相对应,但是具体使用又有较大的不同。

pinia核心介绍:

  1. store:与vuex类似。

    Store 是用 defineStore() 定义的,它的第一个参数要求是一个独一无二的名字,这个名字 ,也被用作 id ,是必须传入的, Pinia 将用它来连接 store 和 devtools。为了养成习惯性的用法,将返回的函数命名为 use… 是一个符合组合式函数风格的约定。

    defineStore() 的第二个参数可接受两类值:Setup 函数或 Option 对象。

    import { defineStore } from 'pinia'
    
    // 你可以对 `defineStore()` 的返回值进行任意命名,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。(比如 `useUserStore`,`useCartStore`,`useProductStore`)
    // 第一个参数是你的应用中 Store 的唯一 ID。
    export const useAlertsStore = defineStore('alerts', {
      // 其他配置...
    });
    
  2. State 是 store 中存储数据的地方。通过定义 State,可以在 store 的任何位置访问和修改数据。

    在 Pinia 中,state 被定义为一个返回初始状态的函数。这使得 Pinia 可以同时支持服务端和客户端。

    import { defineStore } from 'pinia'
    
    const useStore = defineStore('storeId', {
      // 为了完整类型推理,推荐使用箭头函数
      state: () => {
        return {
          // 所有这些属性都将自动推断出它们的类型
          count: 0,
          name: 'Eduardo',
          isAdmin: true,
          items: [],
          hasChanged: true,
        }
      },
    })
    
  3. Getter:

    Getter 用来获取从 state 派生的数据,类似于 Vue 组件中的 computed 计算属性。可以通过 defineStore() 中的 getters 属性来定义它们。推荐使用箭头函数,并且它将接收 state 作为第一个参数:

    export const useStore = defineStore('main', {
      state: () => ({
        count: 0,
      }),
      getters: {
        doubleCount: (state) => state.count * 2,
      },
    })
    
  4. actions:

    Action 相当于组件中的 方法。它们可以通过 defineStore() 中的 actions 属性来定义;Action 是一种将异步操作封装在 store中的方式,它是一个可以被调用的函数,也可以接收参数并修改 store 中的状态。 Action应该始终是同步的,并返回一个 Promise 对象,以便在处理异步操作时能够很好地处理结果。

    import { defineStore } from 'pinia'
    
    export const myStore = defineStore('myStore',{ 
      state: () => ({
        message: 'Hello',
      }),
      actions: {
        async fetchMessage() {
          const response = await fetch('http://127.0.0.1:5173/message')
          const data = await response.json()
          this.message = data.message
        },
      },
    })
    

    使用:

    import { useAlertsStore } from 'pinia'
    
    export default {
      setup() {
        const store = useAlertsStore()
    
        function handleClick() {
          store.fetchMessage()
        }
    
        return {
          handleClick,
        }
      },
    }
    

pinia具体使用:

首先还是一个store文件夹,创建在src下面,便于后期维护和管理。(与vuex不同,不再使用统一管理的index.js,而转变为全部各是各的?)

官方的命名建议为:useXxxxxStore。也就是举个例子,我们使用movieList作为一个例子:

  1. 在src文件夹下新建store文件夹,后面所有涉及需要Pinia进行状态管理的代码都放在该文件夹下
  2. 在store文件夹下新建movieListStore.js文件,创建完成后,打开该文件
  3. 在movieListStore.js文件中引入Pinia中的defineStore 方法

在movieListStore.js文件中:

import { defineStore } from 'pinia';

 const useMovieListStore = defineStore('movie', {   // 第一个参数为唯一ID,第二个参数为store的具体配置
  state: () => ({
    isShow: true,
    movies: [],
  }),
  getters: {
    getIsShow() {
      return this.isShow
    },
    getMovies() {
      return this.movies
    },
  },
  actions: {
    setIsShow(value) {
      this.isShow = value
    },
    async fetchMovies() { // 异步方法
      const response = await fetch('https://api.movies.com/movies')
      const data = await response.json()
      this.movies = data
    },
  },
})
export default useMovieListStore 

具体使用:

<template>
  <nav>
    <ul>
      <li v-show="isShow">{{ $route.name }} </li>
      <li><router-link to="/">Home</router-link></li>
      <li><router-link to="/movies">Movies</router-link></li>
    </ul>
  </nav>
</template>

<script>
import { defineComponent } from 'vue'
import { useStore } from 'pinia'

export default defineComponent({
  name: 'Menu',

  setup() {
    const store = useStore('movie'); // 填写对应的你创建的store的唯一ID
	const fun = ()=>{
        store.setIsShow(false);
    }
    return {
      isShow: store.getIsShow(), // 直接调用对应方法
    }
  },
})
</script>

定义store还有另一种方式,定义store的两种方式非常像vue的组合式API和选项式API这两种方式。上面的是选项式API的定义方式,下面是组合式API的定义方式。(和vue中的基本一致)

在 Setup Store 中:

  • ref() 就是 state 属性
  • computed() 就是 getters
  • function() 就是 actions
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  function increment() {
    count.value++
  }

  return { count, increment }
})

下面的仔细地请看那个博客吧。

注意!如果你的vue版本在3.3以下,那么,很有可能会导致错误,不要使用最新的pinia,使用2.0.36版本

1
https://gitee.com/piao-chen/my-blog---frontend-vue.git
git@gitee.com:piao-chen/my-blog---frontend-vue.git
piao-chen
my-blog---frontend-vue
我的博客(前端vueJS)
dev

搜索帮助