vue3+webpack+elementplus+国际化+axios封装+pinia

news2024/11/25 12:43:52

文章目录

  • 创建项目 + eslint + prettier
    • 切换pinia(后补上)
    • 创建项目
    • eslint + prettier
      • 注意
    • 自动格式化
  • element plus
      • 注意
    • element plus icon
      • 注意:
  • 国际化
    • 注意
  • axios 封装

最近菜鸟自己搭建一个项目,想着 vue3 都出来这么久了,再不用 vue3,怕是等我熟悉 vue3 的时候,vue4 都出来了,直接落后时代一个大版本那就难受了!

但是突然从 vue2 转变到用这个 vue3 确实是让人脑壳疼,接下来就把菜鸟踩坑的地方都分享给大家了!

创建项目 + eslint + prettier

首先要知道的就是,既然是公司,那么一般都有一套代码规范,但是菜鸟现在待的是一个生物公司,之前都没有前端这个岗位,所以一切就是靠菜鸟了,那既然是由我定规范,那一定要搞好点,所以就采用了eslint + prettier!

之所以不用 vite,其一就是感觉 webpack 生态比较好,其二 vue2 就是 webpack 的,其三 vite 的一些依赖要自己去下载,感觉是没有 webpack 方便,所以暂时就没转换(不过好像没法体验 Pinia,可以自己把 vuex卸载并 npm Pinia,也可以创建的时候不选 vuex)!

切换pinia(后补上)

菜鸟在写完博客后,马上尝试了一下把 vuex 换成 pinia ,当然仅限创建项目的时候换,要是你都开发完了,那就不要换了!!!

首先就是执行两个命令:

npm install pinia -S
npm uninstall vuex

然后把 main.js 的store换成 pinia
在这里插入图片描述
然后如果是 vuex 换过来的就不用自己创建 store目录和 index.js 文件,否则需要自己创建,将里面的内容改成:

// store/index.js
import { defineStore } from "pinia";
// 1. 定义容器、导出容器
// 参数1:容器的ID,必须是唯一的,后面Pinia会把所有的容器挂载到根容器
// 参数2:一些选项对象,也就是state、getter和action
// 返回值:一个函数,调用即可得到容器实例

export const useMainStore = defineStore("main", {
  // 类似于Vue2组件中的data,用于存储全局状态数据,但有两个要求
  // 1. 必须是函数,目的是为了在服务端渲染的时候避免交叉请求导致的数据状态污染
  // 2. 必须是箭头函数,这样是为了更好的 TS 类型推导
  state: () => {
    return {
      info: "pinia 可以使用",
    };
  },
  getters: {},
  actions: {},
});

// 2. 使用容器中的 state
// 3. 通过 getter 修改 state
// 4. 使用容器中的 action 同步和异步请求

项目中最简单的使用:

js代码

import { useMainStore } from "../../store";
const mainStore = useMainStore();

html代码

<div>{{ mainStore.info }}</div>

创建项目

vue create testpro

然后选择
在这里插入图片描述
之所以不用 ts,首先菜鸟不是很会 ts,第二菜鸟感觉 js 本来就是自由的语言,你给它加上限制不能说不好,只是菜鸟不喜欢而已!

然后路由模式一定要使用 hash 模式,history 模式菜鸟没用过,反正好像是要后端进行配合,不是很好使用!
在这里插入图片描述
然后 css 菜鸟选择的是 scss,这个按照个人喜好就行!

eslint 菜鸟就是选择的 eslint + prettier
在这里插入图片描述
这个菜鸟选的第一个,不想让其提交的时候使用 fix, fix虽好,但是还是自己能全权掌握的更香,而不是交给 fix !
在这里插入图片描述
到这里项目就创建完了,但是配置还没有配置好!

eslint + prettier

因为这个时候,只要你新建一个 .vue 文件,eslint 就跑过来恶心你了,会报错

Component name "xxxxx” should always be multi-word

在这里插入图片描述
但是感觉这个规范确实不需要,所以只需要在 eslint.js 里面加上这一行就行

在这里插入图片描述
方便复制:

"vue/multi-word-component-names": 0,

这个时候你以为一切顺利,然后再敲了几行代码,eslint 就又来了,会报错

Delete eslint(prettier/prettier)

这是因为
在这里插入图片描述
这里就要创建 .prettierrc 文件,并输入以下

{
  "endOfLine": "auto"
}

注意

一定要重启vscode,不然还是会报错!

这里还有一篇文章说的是另一种方法,读者可以尝试:优雅解决:(linebreak-style) Expected linebreaks to be ‘LF‘ but found ‘CRLF‘. (eslint)

这个时候确实万事大吉,但是你如果写的代码最后一行没有换行,那么就会报错

Insert ␍⏎eslintprettier/prettier

但是这个无伤大雅,打个回车就行了!

自动格式化

要使用 eslint 自然需要一个插件(eslint 不像 prettier,prettier 就算没有插件也可以正常使用,不过不能按照 prettier 的规则自动保存罢了):
在这里插入图片描述
在这里插入图片描述
但是如果想保存的时候自动格式化成为我们想要的格式,那么我们该怎么配置?

这个时候就要下载该插件:
在这里插入图片描述
并将 vscode 的 setting.json 设置成这样:

{
  // 让函数(名)和后面的括号之间加个空格
  "javascript.format.insertSpaceBeforeFunctionParenthesis": true,
  // tab 大小为2个空格
  "editor.tabSize": 2,
  // 180 列后换行
  "editor.wordWrapColumn": 180,
  // 显示 markdown 中英文切换时产生的特殊字符
  "editor.renderControlCharacters": true,
  // 用来忽略工程打开的文件夹
  "files.exclude": {
    "**/.vscode": true,
    "**/.DS_Store": true,
    "**/.history": true,
    "**/nbproject": true
  },
  // 失去焦点自动保存
  "files.autoSave": "onFocusChange",
  // 资源管理器确认删除
  "explorer.confirmDelete": false,
  // 新窗口尺寸
  "window.newWindowDimensions": "maximized",
  // typescript更新启用文件移动时导入(就是ts文件移动时重新导入)
  "typescript.updateImportsOnFileMove.enabled": "always",
  // 比较不同时,忽略空白
  "diffEditor.ignoreTrimWhitespace": false,
  "editor.fontWeight": "normal",
  //忽略搜索设置
  "search.exclude": {
    "**/dist": true,
    "**/node_modules/**": true
  },
  // 将prettier设置为默认格式化程序(在编辑器中有可能被其他Formatter占用,所以将prettier设置为默认Formatter)
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  // 保存时自动格式化 (根据根目录下‘.prettierrc文件配置项’)
  "editor.formatOnSave": true,
  // prettier 最长180列
  "prettier.printWidth": 180,
  // prettier 结束随便
  "prettier.endOfLine": "auto"
}

element plus

使用 element plus 自然要使用其最强大的按需引入,全部引入实在是太浪费内存了!

首先我们按照官网的步骤:

npm install -D unplugin-vue-components unplugin-auto-import

按照完事之后,就要配置 webpack 了,对于 webpack 好的人可能不难,但是不好的可能就不太会,所以这里菜鸟还是写一下,官网的 webpack 需要放在 vue.config.js 里面:

const { defineConfig } = require("@vue/cli-service");

// 按需引入element plus
const AutoImport = require("unplugin-auto-import/webpack");
const Components = require("unplugin-vue-components/webpack");
const { ElementPlusResolver } = require("unplugin-vue-components/resolvers");

const port = 8888;

module.exports = defineConfig({
  transpileDependencies: true,
  productionSourceMap: false,
  // 按需引入element plus
  configureWebpack: {
    resolve: {
      alias: {
        components: "@/components",
      },
    },
    plugins: [
      AutoImport({
        resolvers: [ElementPlusResolver()],
      }),
      Components({
        resolvers: [ElementPlusResolver()],
      }),
    ],
  },
  devServer: {
    port,
    proxy: {
      "/Api": {
        target: "http://xxxxx",
        changeOrigin: true, // 如果接口跨域,需要进行这个参数配置
        pathRewrite: {
          "^/Api": "",
        },
        headers: {
          referer: "http://xxxx",
        },
      },
    },
  },
});

然后等你兴高采烈的准备大干一场,并在项目中使用 element plus 时坑就来了,其编译的时候就会报错:

Module not found: Error: Can’t resolve ‘element-plus/es’ in
Module not found: Error: Can’t resolve ‘element-plus/es/components/base/style/css’ in

这个问题就是你没有安装 element plus 只安装了两个自动导入的插件而已,所以还要执行

npm install element-plus --save

注意

1、
如果你在 script 中使用了 ElMessage ,那么eslint 会报错没有引入,但是其实是没问题的,只需要在 ElMessage 之前加上该代码:

// eslint-disable-next-line

2、有的时候 element plus 版本高了也会报错,详情见:vue3引入element-plus报错解决方案

element plus icon

使用 element plus icon 就和使用其他组件是一样的,唯一的区别就是要引入

import { } from “@element-plus/icons-vue”;

具体引入什么就是去官网点击图标,将复制下来的引入就行!

注意:

上面 npm 了 element-plus,那么这里的图标可以直接引用,不需要 npm 图标库了!

还有一个坑的地方就是按需引入,但是菜鸟发现按需引入确实可以,但是使用的是时候就不能是官网复制下来的,而是不知道哪里复制的,所以暂时不推荐使用!

按需引用参考:
1、Element Plus Icon图标自动引入
2、Vue3!ElementPlus!更加优雅的使用Icon

国际化

首先便是安装国际化库

npm i vue-i18n

在项目中,我们一般会新建一个文件夹专门存放 i18n 的配置

目录结构如下:
在这里插入图片描述

然后新建 i18n.js 文件,引入 vue-i18n,vue-i18n 使用 createI18n 创建实例:

import { createI18n } from "vue-i18n";
import EN from "./en/en";
import CN from "./cn/cn";

const message = {
  cn: {
    ...CN,
  },
  en: {
    ...EN,
  },
};

const i18n = createI18n({
  locale: "cn", // 设置语言类型
  legacy: false, // 如果要支持compositionAPI,此项必须设置为false;
  globalInjection: true, // 全局注册$t方法
  messages: message,
});

export default i18n;

然后 cn / en 里面的文件结构如下:

在这里插入图片描述

内容由自己定义,这里给个例子:

export default {
  username: "用户名",
  password: "密码",
  passwordtip: "请输入密码",
  signIn: "登录",
  signOut: "退出登录",
  signInerr: "登录失败",
};

英文的与之对应即可!

然后便是在 main.js 中引入国际化
在这里插入图片描述

注意

1、如果要在 script 中使用国际化方法,需要结构出 t 方法,html 中可以直接使用 $t(),如下:

import { useI18n } from "vue-i18n";

//  解构出t方法
const { t } = useI18n(); // 先调用此方法,然后再使用

// eslint-disable-next-line
ElMessage({
   message: t("signInerr"),
   type: "error",
 });

2、如果要获取值,必须这样使用:

js代码:

// 切换中英文
import { useI18n } from "vue-i18n";
const { locale } = useI18n(); // 先调用此方法,然后再使用
const changeLang = (msg) => {
  locale.value = msg;
  localStorage.setItem("LANG", msg);
};
const options = [
  {
    value: "cn",
    label: "中文",
  },
  {
    value: "en",
    label: "英文",
  },
];

html:

<el-select v-model="locale" @change="changeLang">
  <el-option
    v-for="item in options"
    :key="item.value"
    :label="item.label"
    :value="item.value"
  />
</el-select>

axios 封装

// 对你引用的第三方网络请求框架进行封装

import axios from "axios";

if (process.env.NODE_ENV == "development") {
  axios.defaults.baseURL = "/Api";
} else if (process.env.NODE_ENV == "production") {
  axios.defaults.baseURL = "";
}

export function request(config) {
  // 1. 创建axios的实例
  const instance = axios.create({
    timeout: 15000,
  });
  //2. 使用axios拦截器
  //2.1 请求拦截
  instance.interceptors.request.use(
    (conF) => {
      //如果不返回,则真正的请求被拦截了,用户就会打印err
      // *** 一般进行的操作 ***
      // 1. config中的一些信息不符合服务器要求,就可以在这修改,在创建实例时也可以
      // 2. 每次发送网络请求时,都希望在界面中显示一个请求的图标
      // 3. 某些网络请求(登陆[token]),必须携带一些特殊的信息
      //    解释:判断请求是什么,如果是特殊的请求,就看看里面有没有token,要是没有,就让其去登陆
      try {
        const token = localStorage.getItem("token");
        token ? (config.headers.Token = token) : null;
      } catch {
        throw new Error("没有token");
      }
      // console.log(conF);
      return conF;
    },
    (err) => {
      console.log(err);
      // eslint-disable-next-line
      ElMessage({
        showClose: true,
        message: err,
      });
    }
  );
  //2.2 响应拦截
  instance.interceptors.response.use(
    (res) => {
      console.log(res);
      //更新token
      if (res.status == 200) {
        // 要根据后台返回的token自行赋值
        if (res.data.data.token) {
          localStorage.setItem("token", res.data.data.token);
        }
      }
      return res.data;
    },
    (error) => {
      if (error.response.status) {
        switch (error.response.status) {
          // 401: 未登录
          case 401:
            // eslint-disable-next-line
            ElMessage({
              showClose: true,
              message: "未登录",
            });
            break;
          // 403 token过期
          // 登录过期对用户进行提示
          // 清除本地token对象
          // 跳转登录页面
          case 403:
            // eslint-disable-next-line
            ElMessage({
              showClose: true,
              message: "登录过期,请重新登录",
            });
            // 清除token
            localStorage.removeItem("token");
            break;
          // 404请求不存在
          case 404:
            // eslint-disable-next-line
            ElMessage({
              showClose: true,
              message: "网络请求不存在",
            });
            break;
          case 500:
            // eslint-disable-next-line
            ElMessage({
              showClose: true,
              message: "Request failed with status code 500",
            });
            break;
          // 其他错误,直接抛出错误提示
          default:
            console.log(error);
            // eslint-disable-next-line
            ElMessage({
              showClose: true,
              message: error.response.data.message,
            });
        }
        return Promise.reject(error.response);
      } else {
        console.log(error);
        // eslint-disable-next-line
        ElMessage({
          showClose: true,
          message: "服务器异常!",
        });
      }
    }
  );
  //3. 真正的发送请求
  return instance(config);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1213923.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

A股风格因子看板 (2023.11 第10期)

该因子看板跟踪A股风格因子&#xff0c;该因子主要解释沪深两市的市场收益、刻画市场风格趋势的系列风格因子&#xff0c;用以分析市场风格切换、组合风格暴 露等。 今日为该因子跟踪第10期&#xff0c;指数组合数据截止日2023-10-31&#xff0c;要点如下 近1年A股风格因子收益…

操作系统课程设计

操作系统课程设计 介绍 1. 系统介绍 具有进程管理&#xff0c;磁盘文件管理的操作系统&#xff0c;用于熟悉操作系统中CPU运行的三种状态&#xff0c;运行、就绪、阻塞。对于文件磁盘管理系统&#xff0c;具有相应的文件读取、写入、删除操作。 2. 运行系统的基础环境 运行…

demo(二)eurekaribbon----服务注册、提供与消费

前一篇实现了服务注册中心的搭建&#xff0c;并提供服务注册到注册中心上。在之前的基础上&#xff0c;实现服务消费。 一、相关介绍 1、RestTemplate工具 2、LoadBalanced注解 二、ribbon示例&#xff1a; 先启动eureka-service注册中心&#xff0c;再将eureka-client修改…

Java代码实现贪吃蛇游戏

一、创建新项目 创建一个新的项目&#xff0c;并命名。创建一个名为images的文件夹用来存放游戏相关图片。然后再在项目的src文件下创建一个com.xxx.view的包用来存放所有的图形界面类&#xff0c;创建一个com.xxx.controller的包用来存放启动的入口类(控制类)。如下所示&…

Day31力扣打卡

打卡记录 由子序列构造的最长回文串的长度&#xff08;区间DP&#xff09; 先将两个字符串合并&#xff0c;再仿照 最长回文子序列 的做法&#xff0c;从中间开始往外进行遍历&#xff0c;由于是两个字符串&#xff0c;在 最长回文子序列 的做法上需要满足 len(word1) < j …

基于PHP的化妆品销售网站,MySQL数据库,PHPstudy,前台用户+后台管理,完美运行,有一万多字论文

目录 演示视频 基本介绍 论文截图 系统截图 演示视频 基本介绍 基于PHP的化妆品销售网站&#xff0c;MySQL数据库&#xff0c;PHPstudy&#xff0c;原生PHP&#xff0c;前台用户后台管理&#xff0c;完美运行&#xff0c;有一万多字论文。 前台功能&#xff1a;用户的注册…

视频剪辑全自动软件,批量剪辑去重+去水印+背景虚化+ai智能配音

软件介绍 在如今的手机时代&#xff0c;人们拍摄视频的频率越来越高&#xff0c;但大多数人往往因为缺乏专业的剪辑工具而不得不让这些珍贵的视频素材埋没在海洋中。而菜鸟视频剪辑助手的出现&#xff0c;让这些人的生活变得更为便捷。菜鸟视频剪辑助手是一款简单易用的视频剪…

【React】React-Redux基本使用

容器组件和 UI 组件 所有的 UI 组件都需要有一个容器组件包裹 容器组件来负责和 Redux 打交道&#xff0c;可以随意使用 Redux 的API UI 组件无任何 Redux API 容器组件用于处理逻辑&#xff0c;UI 组件只会负责渲染和交互&#xff0c;不处理逻辑 在我们的生产当中&#xff0…

在线聊天系统,即时通讯系统

在线聊天&#xff0c;即时通讯系统 可以添加好友&#xff0c;在线聊天&#xff0c;添加群聊&#xff0c;群聊&#xff0c;发送各种类型的文件&#xff0c;文字&#xff0c;图片&#xff0c; 还有各种表情包&#xff0c;系统基于springboot和websocket网络通讯&#xff0c;类似于…

Python---数据序列类型之间的相互转换

list()方法&#xff1a;把某个序列类型的数据转化为列表 # 1、定义元组类型的序列 tuple1 (10, 20, 30) print(list(tuple1))# 2、定义一个集合类型的序列 set1 {a, b, c, d} print(list(set1))# 3、定义一个字典 dict1 {name:刘备, age:18, address:蜀中} print(list(dict1…

AI机器学习实战 | 使用 Python 和 scikit-learn 库进行情感分析

专栏集锦&#xff0c;大佬们可以收藏以备不时之需 Spring Cloud实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏&#xff1a;https:/…

服务器监控及其监控工具

随着互联网技术的不断发展&#xff0c;服务器成为现代企业中不可或缺的一环。对于很多企业来说&#xff0c;服务器故障会给公司的日常工作和财务带来不小的影响。这时&#xff0c;服务器监控成为了保障服务器高效安全运行的一项重要工作。有许多监控工具可以帮助我们更好地监控…

【Qt-23】基于QCharts绘制曲线图

一、QChart简介 QChart是Qt中专门用于绘制图表的模块&#xff0c;支持折线图、柱状图、饼图等常见类型。其主要组成部分有&#xff1a; QChart&#xff1a;整个图表的容器&#xff0c;管理图表中的所有数据和图形属性QChartView&#xff1a;继承自QGraphicsView&#xff0c;用于…

分享一个在线免费制作和视频合成gif的网站

一、打开网站 在线制作高清gif动图-视频转gif表情工具-图片合成软件-gif.cn_GIF中文网 如图 二、可以选择gif合成&#xff0c;也就是把多张图片合成gif 效果图&#xff0c;我用了三张图片。 三、可以选择视频转gif。 效果图 四、完

Postman的常规断言/动态参数断言/全局断言

近期在复习Postman的基础知识&#xff0c;在小破站上跟着百里老师系统复习了一遍&#xff0c;也做了一些笔记&#xff0c;希望可以给大家一点点启发。 断言&#xff0c;包括状态码断言和业务断言&#xff0c;状态码断言有一个&#xff0c;业务断言有多个。 一&#xff09;常规的…

Zookeeper学习笔记(1)—— 基础知识

Zookeeper概述 Zookeeper 是一个开源的分布式的&#xff0c;为分布式框架提供协调服务的 Apache 项目 工作机制 Zookeeper从设计模式角度来理解&#xff1a;是一个基于观察者模式设计的分布式服务管理框架&#xff0c;它负责存储和管理大家都关心的数据&#xff0c;然后接受…

相对强弱指标 RSI

SMA&#xff08;A,B,1)MA AA ,一天前的收盘价&#xff1b; BB&#xff0c;如果时涨的&#xff0c;把涨幅返回&#xff1b; CC,12天的涨幅占12天全部涨跌幅的多少&#xff1b; 画一条50 的线条。

java初探之代理模式

代理模式 代理模式一般有三种角色&#xff1a; 没有使用代理模式的话可能就会直接去操作真实的对象 加入代理模式就是加入了 隔离 把我们的真实对象与调用者隔离了一下(代理对象) 代理对象的好处&#xff1f; 使用者(client)跟真实的对象是没有直接的交集的。不会直接操作到…

蓝桥杯算法双周赛心得——深秋的苹果(二分+贪心分组前缀和)

大家好&#xff0c;我是晴天学长&#xff0c;二分的check函数&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。&#x1f4aa;&#x1f4aa;&#x1f4aa; 1) .深秋的苹果 问题描述 当深秋的苹果树丰收时&#xff0c;村庄的居民们兴致勃勃地采摘着红彤…

c语言从入门到实战——数组指针与函数指针

数组指针与函数指针 前言1. 字符指针变量2. 数组指针变量2.1 数组指针变量是什么&#xff1f;2.2 数组指针变量怎么初始化? 3. 二维数组传参的本质4. 函数指针变量4.1 函数指针变量的创建4.2 函数指针变量的使用4.3 两段有趣的代码4.3.1 typedef关键字 5. 函数指针数组6. 转移…