Vue2 项目常用配置合集:多语言、SVG 图标、代码格式化、权限指令 + 主题切换

在 Vue2 项目开发中,合理的基础配置能显著提升开发效率、规范代码风格并增强项目可维护性。本文整理了 4 个高频实用配置:多语言(i18n)、SVG 图标组件、代码格式化(ESLint + Prettier)、权限控制指令、主题切换,附上可复用代码和配置说明,适用于大多数 Vue2 业务项目

一、多语言配置(vue-i18n)

多语言是中后台系统、国际化产品的核心需求,基于 vue-i18n 实现语言切换与文案管理,支持本地存储记忆语言偏好。

1.1 安装依赖

bash 复制代码
# Vue2 需使用 vue-i18n@8.x 版本(9.x 仅支持 Vue3)
npm install vue-i18n@8 --save

1.2 完整配置代码

1.2.1 核心配置文件(src/i18n/index.js)

javascript 复制代码
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import zhCN from './langs/zh-CN' // 中文文案
import enUS from './langs/en-US' // 英文文案
import { I18N_CONFIG, STORAGE_KEYS } from '@/constants' // 常量配置

// 注册 i18n 插件
Vue.use(VueI18n)

// 语言包集合(可扩展更多语言:如 ja-JP 日语、ko-KR 韩语)
const messages = {
  'zh-CN': zhCN,
  'en-US': enUS,
}

/**
 * 从本地存储获取语言设置,无则使用默认语言
 */
const getLanguage = () => {
  return localStorage.getItem(STORAGE_KEYS.LANGUAGE) || I18N_CONFIG.defaultLocale
}

// 创建 i18n 实例
const i18n = new VueI18n({
  locale: getLanguage(), // 当前语言(优先本地存储)
  messages, // 语言包
  silentTranslationWarn: true, // 关闭「未找到翻译」警告(避免控制台冗余)
  silentFallbackWarn: true, // 关闭「回退语言」警告
  fallbackLocale: 'zh-CN', // 翻译缺失时的回退语言
})

export default i18n

1.2.2 英文语言包(src/i18n/langs/en-US.js)

js 复制代码
export default {
  route: {
    dashboard: 'Dashboard',
    system: 'System',
    user: 'User',
    role: 'Role',
    menu: 'Menu',
    monitor: 'Monitor',
    job: 'Job',
    login: 'Login',
    error: 'Error',
    404: '404',
    401: '401',
    profile: 'Profile',
   }
}

1.2.3 中文语言包(src/i18n/langs/zh-CN.js)

js 复制代码
export default {
  route: {
    dashboard: '首页',
    system: '系统管理',
    user: '用户管理',
    role: '角色管理',
    menu: '菜单管理',
    monitor: '系统监控',
    job: '定时任务',
    login: '登录',
    error: '错误页面',
    404: '404',
    401: '401',
    profile: '个人中心',
  }
}

1.3 配套常量与使用方式

  • 常量配置(src/constants/index.js):定义默认语言、存储键名
  • 语言包示例:按模块划分文案(如 common、user、menu)
  • 全局注册:在 main.js 注入 i18n 实例
  • 使用方式:模板中 {{ $t('common.confirm') }},脚本中 this.$t('common.success')

二、SVG 图标组件(svg-sprite-loader)

使用 SVG 图标比图片图标更清晰、可缩放,配合 svg-sprite-loader 实现按需加载,封装通用 SvgIcon 组件。

2.1 安装依赖

bash 复制代码
npm install svg-sprite-loader --save-dev

2.2 Webpack 配置(vue.config.js)

javascript 复制代码
const path = require('path')

// 路径解析辅助函数
function resolve(dir) {
  return path.join(__dirname, dir)
}

module.exports = {
  chainWebpack: config => {
    // 1. 清除默认的 svg 处理规则(避免与 svg-sprite-loader 冲突)
    config.module.rules.delete('svg')
    
    // 2. 配置 svg-sprite-loader 处理 src/icons 目录下的 SVG
    config.module
      .rule('icons')
      .test(/.svg$/) // 匹配 svg 文件
      .include.add(resolve('src/icons')) // 只处理 src/icons 目录
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]' // 生成的 symbol id 格式:icon-文件名
      })
      .end()
  }
}

2.3 通用 SVG 组件(src/components/SvgIcon/index.vue)

vue 复制代码
<template>
  <!-- 外部 SVG 图标(http/https 链接) -->
  <div
    v-if="isExternal"
    :style="styleExternalIcon"
    class="svg-external-icon svg-icon"
    v-on="$listeners"
  />
  <!-- 内部 SVG 图标(src/icons 目录下) -->
  <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
    <use :xlink:href="iconName" /> <!-- 关联 svg-sprite 的 symbol id -->
  </svg>
</template>

<script>
export default {
  name: 'SvgIcon', // 组件名(必须,便于注册和调试)
  props: {
    iconClass: {
      type: String,
      required: true, // 图标名称(必填)
    },
    className: {
      type: String,
      default: '', // 额外类名(用于自定义样式)
    },
  },
  computed: {
    // 判断是否为外部 SVG 图标(http/https/mailto/tel 开头)
    isExternal() {
      return /^(https?:|mailto:|tel:)/.test(this.iconClass)
    },
    // 内部图标:拼接 symbol id(与 webpack 配置的 symbolId 一致)
    iconName() {
      return `#icon-${this.iconClass}`
    },
    // 拼接最终的类名
    svgClass() {
      return this.className ? `svg-icon ${this.className}` : 'svg-icon'
    },
    // 外部图标样式(通过 mask 实现 SVG 效果)
    styleExternalIcon() {
      return {
        mask: `url(${this.iconClass}) no-repeat 50% 50%`,
        '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`,
        maskSize: 'cover',
        '-webkit-mask-size': 'cover'
      }
    },
  },
}
</script>

<style scoped>
/* 基础 SVG 样式:继承父元素颜色(fill: currentColor) */
.svg-icon {
  width: 1em;
  height: 1em;
  fill: currentColor;
  overflow: hidden;
  vertical-align: middle; /* 对齐文字 */
}

/* 外部 SVG 图标样式 */
.svg-external-icon {
  background-color: currentColor;
  display: inline-block;
}
</style>

2.4 自动导入与使用

js 复制代码
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon'

// 注册全局组件
Vue.component('svg-icon', SvgIcon)

// 自动导入所有 SVG 图标
const req = require.context('./svg', false, /\.svg$/)
const requireAll = requireContext => {
  const files = requireContext.keys()
  files.forEach(key => {
    const name = key.replace(/^\.\/(.*)\.\w+$/, '$1')
    const component = requireContext(key)
  })
  return files.map(requireContext)
}
requireAll(req)
  • 图标自动导入(src/icons/index.js):批量导入目录下所有 SVG
  • 全局注册:在 main.js 注册 SvgIcon 组件
  • 使用方式:<svg-icon icon-class="user" className="text-red-500" />

三、代码格式化配置(ESLint + Prettier)

统一代码风格,减少团队协作冲突,自动修复格式问题。

3.1 安装依赖

bash 复制代码
npm install eslint prettier eslint-plugin-vue eslint-config-prettier eslint-plugin-prettier @babel/eslint-parser --save-dev

3.2 核心配置文件

3.2.1 Prettier 配置(.prettierrc)

json 复制代码
{
  "semi": false, // 不加分号
  "singleQuote": true, // 使用单引号
  "printWidth": 100, // 每行最大长度(超过自动换行)
  "tabWidth": 2, // 缩进 2 个空格
  "useTabs": false, // 不使用制表符(Tab)
  "trailingComma": "es5", // 对象/数组末尾加逗号(ES5 兼容)
  "bracketSpacing": true, // 对象字面量前后加空格({ foo: bar })
  "arrowParens": "avoid", // 箭头函数参数只有一个时不加括号(x => x)
  "vueIndentScriptAndStyle": true, // Vue 组件中 script 和 style 缩进与 template 一致
  "htmlWhitespaceSensitivity": "ignore" // HTML 空格不敏感
}

3.2.2 ESLint 配置(.eslintrc.js)

javascript 复制代码
module.exports = {
  root: true, // 标识为根配置
  env: {
    node: true,
    jest: true,
    browser: true
  },
  extends: [
    'plugin:vue/essential',
    'eslint:recommended',
    'plugin:prettier/recommended'
  ],
  parserOptions: {
    parser: '@babel/eslint-parser',
    requireConfigFile: false,
    ecmaVersion: 2020,
    sourceType: 'module'
  },
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-unused-vars': [
      'warn',
      {
        vars: 'all',
        args: 'after-used',
        ignoreRestSiblings: true,
        argsIgnorePattern: '^_',
        varsIgnorePattern: '^_'
      }
    ]
  }
}

3.3 脚本与使用

  • 配置脚本(package.json):添加 lintlint:fix 命令
  • 忽略文件:.prettierignore + .eslintignore 排除无需格式化的文件
  • 使用方式:npm run lint 检查格式,npm run lint:fix 自动修复

四、权限控制指令(v-permission)

基于用户权限动态显示 / 隐藏 DOM 元素,适用于按钮、菜单等权限控制场景。

4.1 指令实现(src/directives/permission.js)

javascript 复制代码
import store from '@/store' // Vuex 存储用户权限信息

export default {
  // 指令绑定到元素时执行
  inserted(el, binding) {
    checkPermission(el, binding)
  },
  // 指令所在组件更新时执行(如权限变化后)
  update(el, binding) {
    checkPermission(el, binding)
  },
}

/**
 * 权限校验核心逻辑
 * @param el 指令绑定的 DOM 元素
 * @param binding 指令绑定信息(value 为权限标识数组)
 */
function checkPermission(el, binding) {
  const { value } = binding

  // 1. 校验权限标识格式(必须是数组)
  if (!value || !(value instanceof Array) || value.length === 0) {
    console.warn("权限指令使用错误!需指定权限标识数组,例如:v-permission="['admin','editor']"")
    el.parentNode?.removeChild(el) // 格式错误时隐藏元素
    return
  }

  // 2. 获取用户权限和角色(从 Vuex 中获取)
  const userPermissions = store.getters['user/permissions'] // 权限列表(如 ['user:list'])
  const userRoles = store.getters['user/roles'] // 角色列表(如 ['admin'])

  // 3. 权限判断:拥有任一所需权限 或 是管理员 → 显示元素
  const hasPermission = userPermissions.some(perm => value.includes(perm)) || userRoles.includes('admin')

  // 4. 无权限时移除元素
  if (!hasPermission) {
    el.parentNode?.removeChild(el)
  }
}

4.2 全局注册与使用

  • 注册指令(src/directives/index.js):全局注册 v-permission
  • 导入指令:在 main.js 引入
  • 使用方式:<el-button v-permission="['admin','user:edit']">编辑</el-button>

五、主题色配置(支持多主题切换)

基于 CSS 变量 + SCSS 实现主题切换,适配 Element UI 组件样式,支持默认、暗黑、蓝色三种主题,可扩展自定义主题。

5.1 主题配置常量(src/constants/theme.js)

javascript 复制代码
// 主题配置:定义各主题的颜色变量
export const themes = {
  default: {
    // 主色调
    primaryColor: '#409EFF',
    // 功能色
    successColor: '#67C23A',
    warningColor: '#E6A23C',
    dangerColor: '#F56C6C',
    infoColor: '#909399',
    // 基础色
    textColor: '#303133',
    borderColor: '#DCDFE6',
    backgroundColor: '#FFFFFF',
    // 布局色
    sidebarBgColor: '#ffffff',
    sidebarTextColor: '#303133',
    sidebarActiveTextColor: '#409EFF',
  },
  dark: {
    primaryColor: '#409EFF',
    successColor: '#67C23A',
    warningColor: '#E6A23C',
    dangerColor: '#F56C6C',
    infoColor: '#909399',
    textColor: '#E5EAF3',
    borderColor: '#4C4D4F',
    backgroundColor: '#141414',
    sidebarBgColor: '#1f1f1f',
    sidebarTextColor: '#bfcbd9',
    sidebarActiveTextColor: '#409EFF',
  },
  blue: {
    primaryColor: '#1890ff',
    successColor: '#52c41a',
    warningColor: '#faad14',
    dangerColor: '#f5222d',
    infoColor: '#909399',
    textColor: '#303133',
    borderColor: '#DCDFE6',
    backgroundColor: '#FFFFFF',
    sidebarBgColor: '#001529',
    sidebarTextColor: '#bfcbd9',
    sidebarActiveTextColor: '#1890ff',
  },
}

// 主题列表(用于下拉选择框)
export const themeList = [
  { label: '默认主题', value: 'default' },
  { label: '暗黑主题', value: 'dark' },
  { label: '蓝色主题', value: 'blue' }
]

// 从本地存储获取当前主题(无则默认)
export function getTheme() {
  return localStorage.getItem('theme') || 'default'
}

// 设置并应用主题
export function setTheme(theme) {
  localStorage.setItem('theme', theme)
  applyTheme(theme)
}

// 应用主题核心逻辑:设置 CSS 变量 + 切换 body 类名
export function applyTheme(theme) {
  const themeConfig = themes[theme]
  if (!themeConfig) return

  // 1. 移除所有主题类,添加当前主题类
  document.body.classList.remove('theme-default', 'theme-dark', 'theme-blue')
  document.body.classList.add(`theme-${theme}`)

  // 2. 设置全局 CSS 变量(供组件使用)
  Object.keys(themeConfig).forEach(key => {
    document.documentElement.style.setProperty(`--${key}`, themeConfig[key])
  })
}

5.2 SCSS 主题样式(src/styles/theme.scss)

s 复制代码
@use './variables.scss' as *;
@use './mixin.scss' as *;

// 全局 CSS 变量(默认值)
:root {
  --primaryColor: #409eff;
  --successColor: #67c23a;
  --warningColor: #e6a23c;
  --dangerColor: #f56c6c;
  --infoColor: #909399;
  --textColor: #303133;
  --borderColor: #dcdfe6;
  --backgroundColor: #f5f7fa;
  --sidebarBgColor: #304156;
  --sidebarTextColor: #bfcbd9;
  --sidebarActiveTextColor: #409eff;
}

// -------------------------- 主题专属样式 --------------------------
// 默认主题
.theme-default {
  // 按钮样式
  .el-button--primary {
    background-color: #409eff;
    border-color: #409eff;

    &:hover {
      background-color: #66b1ff;
      border-color: #66b1ff;
    }

    &:active {
      background-color: #3a8ee6;
      border-color: #3a8ee6;
    }
  }

  // 表格样式
  .el-table {
    background-color: #fff;

    th {
      background-color: #f5f7fa;
      color: #303133;
      font-weight: 500;
    }

    td {
      color: #606266;
    }

    tr:hover > td {
      background-color: rgba(64, 158, 255, 0.05) !important;
    }

    .el-table__row--striped {
      background-color: #fafafa;
    }
  }
}

// 暗黑主题(重点适配 Element UI 组件)
.theme-dark {
  // 卡片样式
  .el-card {
    background-color: #1f1f1f;
    border-color: #4c4d4f;
    color: #a8abb2;

    .el-card__header {
      border-bottom-color: #4c4d4f;
      color: #e5eaf3;
    }
  }

  // 表格样式
  .el-table {
    background-color: #1f1f1f;
    color: #e5eaf3;

    th {
      background-color: rgba(#141414, 0.6) !important;
      color: #e5eaf3;
    }

    td {
      border-bottom: 1px solid rgba(#4c4d4f, 0.1);
      color: #a8abb2;
    }

    tr:hover > td {
      background-color: rgba(255, 255, 255, 0.05) !important;
    }
  }

  // 输入框样式
  .el-input__inner {
    background-color: #1f1f1f;
    border-color: #4c4d4f;
    color: #a8abb2;

    &:hover {
      border-color: #606266;
    }

    &:focus {
      border-color: #409eff;
    }
  }

  // 对话框、下拉框、提示框等组件样式(完整代码见上文)
}

// 蓝色主题
.theme-blue {
  .el-button--primary {
    background-color: #1890ff;
    border-color: #1890ff;

    &:hover {
      background-color: #40a9ff;
      border-color: #40a9ff;
    }
  }

  .el-menu-item.is-active {
    background-color: rgba(24, 144, 255, 0.1) !important;
  }
}

// -------------------------- 全局通用样式 --------------------------
body {
  color: var(--textColor);
  background-color: var(--backgroundColor);
  transition: background-color 0.3s ease; // 平滑过渡
}

// 侧边栏样式
.sidebar-container {
  background-color: var(--sidebarBgColor);

  .el-menu {
    background-color: var(--sidebarBgColor);

    .el-menu-item,
    .el-submenu__title {
      color: var(--sidebarTextColor);

      &.is-active {
        color: var(--sidebarActiveTextColor);
      }
    }
  }
}

// 按钮、表单、卡片等全局样式(使用 CSS 变量,自动适配主题)
.el-button--primary {
  background-color: var(--primaryColor);
  border-color: var(--primaryColor);
}

.el-input__inner {
  color: var(--textColor);
  background-color: var(--backgroundColor);
  border-color: var(--borderColor);
}

.el-card {
  background-color: var(--backgroundColor);
  border-color: var(--borderColor);
}

5.3 主题初始化与切换

5.3.1 初始化主题(main.js)

javascript 复制代码
import Vue from 'vue'
import App from './App.vue'
import { getTheme, applyTheme } from '@/constants/theme'
import '@/styles/theme.scss' // 导入主题样式

// 初始化主题(页面加载时执行)
applyTheme(getTheme())

new Vue({
  el: '#app',
  render: h => h(App)
})

5.3.2 主题切换组件(示例)

vue 复制代码
<template>
  <el-select 
    v-model="currentTheme" 
    placeholder="选择主题" 
    size="mini"
    @change="handleThemeChange"
  >
    <el-option 
      v-for="item in themeList" 
      :key="item.value" 
      :label="item.label" 
      :value="item.value"
    ></el-option>
  </el-select>
</template>

<script>
import { getTheme, setTheme, themeList } from '@/constants/theme'

export default {
  data() {
    return {
      themeList,
      currentTheme: getTheme()
    }
  },
  methods: {
    handleThemeChange(theme) {
      setTheme(theme) // 切换并保存主题
      this.currentTheme = theme
      this.$message.success(`已切换至${themeList.find(item => item.value === theme).label}`)
    }
  }
}
</script>

5.4 主题适配说明

  1. CSS 变量优先级 :主题切换时通过 document.documentElement.style.setProperty 动态修改 CSS 变量,覆盖默认值;
  2. Element UI 适配 :通过主题类(如 .theme-dark)针对性修改 Element 组件样式,解决第三方组件主题兼容问题;
  3. 平滑过渡 :在 body 或核心容器添加 transition: background-color 0.3s ease,实现主题切换时的视觉过渡;
  4. 扩展性 :新增主题时,只需在 themes 常量中添加配置,在 theme.scss 中补充专属样式即可。
相关推荐
一键定乾坤4 小时前
npm 源修改
前端
parade岁月4 小时前
Vue 3 响应式陷阱:对象引用丢失导致的数据更新失效
前端
掘金安东尼4 小时前
GPT-6 会带来科学革命?奥特曼最新设想:AI CEO、便宜医疗与全新计算机
前端·vue.js·github
申阳4 小时前
Day 5:03. 基于Nuxt开发博客项目-页面结构组织
前端·后端·程序员
全马必破三4 小时前
React的设计理念与核心特性
前端·react.js·前端框架
ttod_qzstudio4 小时前
替代 TDesign Dialog:用 div 实现可拖拽、遮罩屏蔽的对话框
前端·tdesign
洞窝技术4 小时前
前端人必看的 node_modules 瘦身秘籍:从臃肿到轻盈,Umi 项目依赖优化实战
前端·vue.js·react.js
Asort4 小时前
React函数组件深度解析:从基础到最佳实践
前端·javascript·react.js
golang学习记4 小时前
VS Code + Chrome DevTools MCP 实战:用 AI 助手自动分析网页性能
前端