开启2021学习之旅,主要介绍学习vite2和vue3的实战过程。
本篇主要介绍从零开始搭建Vite2 + Vue3+Element-Plus + Vue-router4 + Vuex + Eslint。
Vite (法语意为 "快速的",发音 /vit/)是一种全新的前端构建工具。
由一个开箱即用的开发服务器 + 一套构建 指令组成。
Vite 利用浏览器原生的 ES 模块支持和基于 esbuild 的依赖预打包来显著提升前端开发体验。
# npm 6.x
npm init @vitejs/app my-vue-app --template vue
# npm 7+, 需要额外的双横线:
npm init @vitejs/app my-vue-app -- --template vue
# yarn
yarn create @vitejs/app my-vue-app --template vue
修改vite.config.js
import path from 'path'
export default defineConfig({
...,
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
components: path.resolve(__dirname, 'src/components'),
assets: path.resolve(__dirname, 'src/assets'),
views: path.resolve(__dirname, 'src/views'),
utils: path.resolve(__dirname, 'src/utils'),
apis: path.resolve(__dirname, 'src/apis'),
},
}
})
scss是一款css预处理语言,是sass的一个升级版本,SCSS 是 Sass 3 引入新的语法,其语法完全兼容 CSS3,并且继承了 Sass 的强大功能。
npm i -d sass node-sass sass-loader
# vite.config.js
export default defineConfig({
...,
css: {
preprocessorOptions: {
scss: {
// @/ 是 src/ 的别名
// 所以这里假设你有 `src/assets/scss/variables.scss` 这个文件
additionalData: `@import "@/assets/scss/variables.scss";`
},
},
}
})
开始引入UI框架,这里使用Element适配vue3版本的element-plus
npm i -s element-plus
借助 vite-plugin-style-import实现按需加载组件,以达到减小项目体积的目
npm install vite-plugin-style-import -D
import styleImport from 'vite-plugin-style-import'
plugins: [
vue(),
styleImport({
libs: [
{
libraryName: 'element-plus',
esModule: true,
ensureStyleFile: true,
resolveStyle: (name) => {
name = name.slice(3);
return `element-plus/packages/theme-chalk/src/${name}.scss`;
},
resolveComponent: (name) => {
return `element-plus/lib/${name}`;
},
},
],
})
]
// 如果要使用.scss样式文件,则需要引入base.scss文件
// import 'element-plus/packages/theme-chalk/src/base.scss'
import 'element-plus/packages/theme-chalk/src/base.scss'
import {
ElAlert,
ElAside,
ElAutocomplete,
ElAvatar,
ElBacktop,
ElBadge,
ElBreadcrumb,
ElBreadcrumbItem,
ElButton,
ElButtonGroup,
ElCalendar,
ElCard,
ElCarousel,
ElCarouselItem,
ElCascader,
ElCascaderPanel,
ElCheckbox,
ElCheckboxButton,
ElCheckboxGroup,
ElCol,
ElCollapse,
ElCollapseItem,
ElCollapseTransition,
ElColorPicker,
ElContainer,
ElDatePicker,
ElDialog,
ElDivider,
ElDrawer,
ElDropdown,
ElDropdownItem,
ElDropdownMenu,
ElFooter,
ElForm,
ElFormItem,
ElHeader,
ElIcon,
ElImage,
ElInput,
ElInputNumber,
ElLink,
ElMain,
ElMenu,
ElMenuItem,
ElMenuItemGroup,
ElOption,
ElOptionGroup,
ElPageHeader,
ElPagination,
ElPopconfirm,
ElPopover,
ElPopper,
ElProgress,
ElRadio,
ElRadioButton,
ElRadioGroup,
ElRate,
ElRow,
ElScrollbar,
ElSelect,
ElSlider,
ElStep,
ElSteps,
ElSubmenu,
ElSwitch,
ElTabPane,
ElTable,
ElTableColumn,
ElTabs,
ElTag,
ElTimePicker,
ElTimeSelect,
ElTimeline,
ElTimelineItem,
ElTooltip,
ElTransfer,
ElTree,
ElUpload,
ElInfiniteScroll,
ElLoading,
ElMessage,
ElMessageBox,
ElNotification,
} from 'element-plus';
const components = [
ElAlert,
ElAside,
ElAutocomplete,
ElAvatar,
ElBacktop,
ElBadge,
ElBreadcrumb,
ElBreadcrumbItem,
ElButton,
ElButtonGroup,
ElCalendar,
ElCard,
ElCarousel,
ElCarouselItem,
ElCascader,
ElCascaderPanel,
ElCheckbox,
ElCheckboxButton,
ElCheckboxGroup,
ElCol,
ElCollapse,
ElCollapseItem,
ElCollapseTransition,
ElColorPicker,
ElContainer,
ElDatePicker,
ElDialog,
ElDivider,
ElDrawer,
ElDropdown,
ElDropdownItem,
ElDropdownMenu,
ElFooter,
ElForm,
ElFormItem,
ElHeader,
ElIcon,
ElImage,
ElInput,
ElInputNumber,
ElLink,
ElMain,
ElMenu,
ElMenuItem,
ElMenuItemGroup,
ElOption,
ElOptionGroup,
ElPageHeader,
ElPagination,
ElPopconfirm,
ElPopover,
ElPopper,
ElProgress,
ElRadio,
ElRadioButton,
ElRadioGroup,
ElRate,
ElRow,
ElScrollbar,
ElSelect,
ElSlider,
ElStep,
ElSteps,
ElSubmenu,
ElSwitch,
ElTabPane,
ElTable,
ElTableColumn,
ElTabs,
ElTag,
ElTimePicker,
ElTimeSelect,
ElTimeline,
ElTimelineItem,
ElTooltip,
ElTransfer,
ElTree,
ElUpload,
];
const plugins = [
ElInfiniteScroll,
ElLoading,
ElMessage,
ElMessageBox,
ElNotification,
];
const option = { size: 'small', zIndex: 3000 }
export default (app) => {
// element全局配置
app.config.globalProperties.$ELEMENT = option
components.forEach((component) => {
app.component(component.name, component);
});
plugins.forEach((plugin) => {
app.use(plugin);
});
};
import useElement from '@/utils/element.js';
const app = createApp(App)
useElement(app)
app.mount('#app')
# 如果报错 Error: @use rules must be written before any other rules.
# 修改vite.config.js
- additionalData: `@import "assets/scss/variables.scss";`
+ additionalData: `@use "assets/scss/variables.scss" as *;`
Vue Router 是 Vue的路由管理器,它和 Vue.js 的核心深度集成,是Vue的核心插件之一。
npm i -s [email protected]
src目录下新建router目录文件夹
router目录下新建index.js
// 引入vue-router对象
import { createRouter, createWebHistory } from "vue-router";
import Layout from '@/layout'
/**
* 定义路由数组
*/
const routes = [
{// 404路由
name: '404',
path: '404',
component: () => import('/@/views/error/404.vue')
},
{// 401路由
name: '401',
path: '401',
component: () => import('@/views/error/401.vue'),
hidden: true
},
{
name: 'home',
path: "home",
component: () => import("/@/views/home/home.vue"),
}
];
/**
* 创建路由
*/
const router = createRouter({
// hash模式:createWebHashHistory,
// history模式:createWebHistory
history: createWebHistory("/"),
// history:createWebHashHistory(),
routes,
});
/**
* 路由守卫
*/
router.beforeEach((guard) => {
beforeEach.checkAuth(guard, router);
});
/**
* 路由错误回调
*/
router.onError((handler) => {
console.log("error:", handler);
});
/**
* 输出对象
*/
export default router
import { createApp } from 'vue'
import App from './App.vue'
import useElement from '@/utils/element.js';
import router from '@/router/index.js'
const app = createApp(App)
useElement(app)
app.use(router)
app.mount('#app')
npm i vuex@4 -s
在src目录下新建store目录
store目录下新建index.js文件
import { createStore, Store } from 'vuex';
import user from './modules/user';
import getters from './getters'
const store = createStore({
modules: { user },
getters
});
export default store
// src/store/modules/user.js
const state = {
name: 'hello vue3',
age: 18
}
const mutations = {
SET_NAME: (state, name) => {
state.name = name
},
SET_AGE: (state, age) => {
state.age = age
}
}
const actions = {
setName({ commit }, name) {
commit('SET_NAME', name)
},
setAge({ commit }, age) {
commit('SET_AGE', age)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
import { createApp } from 'vue'
import App from './App.vue'
import useElement from '@/utils/element.js';
import router from '@/router/index.js'
import i18n from '@/i18n/index.js'
import store from '@/store/index.js' //++++
const app = createApp(App)
app.use(router)
app.use(store) //++++
app.use(i18n)
useElement(app)
app.mount('#app')
通过vue-i18n实现国际化
npm i vue-i18n@next -s
src目录下新建i18n目录,新建cn.js、en.js多语言配置文件
// src/i18n/cn.js
export default {
message: {
hello: '你好,欢迎使用Vue3'
}
};
// src/i18n/en.js
export default {
message: {
hello: 'Hello Vue3'
}
};
i18n目录下新建index.js
// src/i18n/index.js
import { createI18n } from 'vue-i18n';
import cn from './cn.js';
import en from './en.js';
const messages = {
en: {
...en
},
'zh-cn': {
...cn
}
}
const i18n = createI18n({
locale: localStorage.getItem('lang') || 'zh-cn',
messages
});
export default i18n;
import { createApp } from 'vue'
import App from './App.vue'
import useElement from '@/utils/element.js';
import router from '@/router/index.js'
import i18n from '@/i18n/index.js'
const app = createApp(App)
app.use(router)
app.use(i18n)
useElement(app)
app.mount('#app')
编码过程中,代码规范很重要,采用ESLint可以避免很多编码错误,提高代码可读性,这里采用Airbnb JavaScript 这套代码规范。
npm i -d eslint eslint-config-airbnb-base eslint-plugin-import eslint-plugin-vue
# src目录下新建.eslintrc.js文件,参考如下配置:
module.exports = {
extends: ['plugin:vue/vue3-essential', 'airbnb-base'],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
},
plugins: ['vue'],
rules: {
...
},
};
# 配置ESLint忽略文件,根目录创建.eslintignore文件,内如根据需求添加配置,例如:
/node_modules
/dist
折腾了一两天,基本上按照官网指南进行操作,按步骤即可完成搭建。