尤大的 Vue3.0 已经发布有一阵子了,已经很成熟了。
而且 Element Plus + Vite 也出了一段时间了,是时候该上手体验分享一波了。
主要是要熟练一下 Vue3,好准备用 Vue3 重构一下自己的网站项目: blog-vue-typescript ,计划是过年期间会着手重构这个项目,年后会上线。
1. 初化化项目
全局安装 vite-app
npm?i?-g?vite-app
创建项目
yarn?create?vite-app?<project-name>
#?或者
npm?init?vite-app?<project-name>
进入项目,安装依赖
cd?<project-name>
yarn?#?或?npm?i
运行项目
yarn?dev?
打开浏览器 http://localhost:3000 查看
2. 引入TypeScript
加入 ts 依赖
yarn?add?--dev?typescript
在 项目根目录下创建 TypeScript 的配置文件 tsconfig.json
{
??"compilerOptions":?{
????//?允许从没有设置默认导出的模块中默认导入。这并不影响代码的输出,仅为了类型检查。
????"allowSyntheticDefaultImports":?true,
????
????//?解析非相对模块名的基准目录
????"baseUrl":?".",
????"esModuleInterop":?true,
????//?从?tslib?导入辅助工具函数(比如?__extends,?__rest等)
????"importHelpers":?true,
????//?指定生成哪个模块系统代码
????"module":?"esnext",
????//?决定如何处理模块。
????"moduleResolution":?"node",
????//?启用所有严格类型检查选项。
????//?启用?--strict相当于启用?--noImplicitAny,?--noImplicitThis,?--alwaysStrict,?
????//?--strictNullChecks和?--strictFunctionTypes和--strictPropertyInitialization。
????"strict":?true,
????//?生成相应的 .map文件。
????"sourceMap":?true,
????//?忽略所有的声明文件(?*.d.ts)的类型检查。
????"skipLibCheck":?true,
????//?指定ECMAScript目标版本?
????"target":?"esnext",
????
????//?要包含的类型声明文件名列表
????"types":?[
????],
????"isolatedModules":?true,
????//?模块名到基于 baseUrl的路径映射的列表。
????"paths":?{
??????"@/*":?[
????????"src/*"
??????]
????},
????//?编译过程中需要引入的库文件的列表。
????"lib":?[
??????"ESNext",
??????"DOM",
??????"DOM.Iterable",
??????"ScriptHost"
????]
??},
??"include":?[
????"src/**/*.ts",
????"src/**/*.tsx",
????"src/**/*.vue",
????"tests/**/*.ts",
????"tests/**/*.tsx"
??],
??"exclude":?[
????"node_modules"
??]
}
在 src 目录下新加 shim.d.ts 文件
/*?eslint-disable?*/
import?type?{?DefineComponent?}?from?'vue'
declare?module?'*.vue'?{
??const?component:?DefineComponent<{},?{},?any>
??export?default?component
}
把 main.js 修改成 main.ts
在根目录,打开 Index.html
<script?type="module"?src="/src/main.js"></script>
修改为:
<script?type="module"?src="/src/main.ts"></script>
3. 引入 eslint
安装 eslint prettier 依赖
@typescript-eslint/parser @typescr ipt-eslint/eslint-plugin
为 eslint 对 typescript 支持。
yarn?add?--dev?eslint?prettier?eslint-config-prettier?eslint-plugin-prettier?eslint-plugin-vue?@typescript-eslint/parser?@typescr?ipt-eslint/eslint-plugin
在根目录下建立 eslint 配置文件:.eslintrc.js
module.exports?=?{
??parser:?'vue-eslint-parser',
??parserOptions:?{
????parser:?'@typescript-eslint/parser',
????ecmaVersion:?2020,
????sourceType:?'module',
????ecmaFeatures:?{
??????jsx:?true
????}
??},
??extends:?[
????'plugin:vue/vue3-recommended',
????'plugin:@typescript-eslint/recommended',
????'prettier/@typescript-eslint',
????'plugin:prettier/recommended'
??],
??rules:?{
????'@typescript-eslint/ban-ts-ignore':?'off',
????'@typescript-eslint/explicit-function-return-type':?'off',
????'@typescript-eslint/no-explicit-any':?'off',
????'@typescript-eslint/no-var-requires':?'off',
????'@typescript-eslint/no-empty-function':?'off',
????'vue/custom-event-name-casing':?'off',
????'no-use-before-define':?'off',
????//?'no-use-before-define':?[
????//???'error',
????//???{
????//?????functions:?false,
????//?????classes:?true,
????//???},
????//?],
????'@typescript-eslint/no-use-before-define':?'off',
????//?'@typescript-eslint/no-use-before-define':?[
????//???'error',
????//???{
????//?????functions:?false,
????//?????classes:?true,
????//???},
????//?],
????'@typescript-eslint/ban-ts-comment':?'off',
????'@typescript-eslint/ban-types':?'off',
????'@typescript-eslint/no-non-null-assertion':?'off',
????'@typescript-eslint/explicit-module-boundary-types':?'off',
????'@typescript-eslint/no-unused-vars':?[
??????'error',
??????{
????????argsIgnorePattern:?'^h$',
????????varsIgnorePattern:?'^h$'
??????}
????],
????'no-unused-vars':?[
??????'error',
??????{
????????argsIgnorePattern:?'^h$',
????????varsIgnorePattern:?'^h$'
??????}
????],
????'space-before-function-paren':?'off',
????quotes:?['error',?'single'],
????'comma-dangle':?['error',?'never']
??}
};
建立 prettier.config.js
module.exports?=?{
??printWidth:?100,
??tabWidth:?2,
??useTabs:?false,
??semi:?false,?//?未尾逗号
??vueIndentScriptAndStyle:?true,
??singleQuote:?true,?//?单引号
??quoteProps:?'as-needed',
??bracketSpacing:?true,
??trailingComma:?'none',?//?未尾分号
??jsxBracketSameLine:?false,
??jsxSingleQuote:?false,
??arrowParens:?'always',
??insertPragma:?false,
??requirePragma:?false,
??proseWrap:?'never',
??htmlWhitespaceSensitivity:?'strict',
??endOfLine:?'lf'
}
4. vue-router、vuex
yarn?add?vue-router@next?vuex@next
4.1 vuex
在根目录下创建 store/index.ts
import?{?InjectionKey?}?from?'vue'
import?{?createStore,?Store?}?from?'vuex'
export?interface?State?{
??count:?number
}
export?const?key:?InjectionKey<Store<State>>?=?Symbol()
export?const?store?=?createStore<State>({
??state()?{
????return?{
??????count:?0
????}
??},
??mutations:?{
????increment(state)?{
??????state.count++
????}
??}
})
main.ts 修改
import?{?createApp?}?from?'vue'
import?{?store,?key?}?from?'./store'
import?App?from?'./App'
import?'./index.css'
const?app?=?createApp(App)
app.use(store,?key)
app.mount('#app')
components/HelloWord.vue 修改
<template>
??<h1>{{?msg?}}</h1>
??<button?@click="inCrement">?count?is:?</button>
??<p>{{?count?}}</p>
</template>
<script>
??import?{?defineComponent,?computed?}?from?'vue'
??import?{?useStore?}?from?'vuex'
??import?{?key?}?from?'../store'
??export?default?defineComponent({
????name:?'HelloWorld',
????props:?{
??????msg:?{
????????type:?String,
????????default:?''
??????}
????},
????setup()?{
??????const?store?=?useStore(key)
??????const?count?=?computed(()?=>?store.state.count)
??????return?{
????????count,
????????inCrement:?()?=>?store.commit('increment')
??????}
????}
??})
</script>
4.2 vue-router
在 src 目录下建立 router/index.ts,内容如下:
import?{?createRouter,?createWebHistory,?RouteRecordRaw?}?from?"vue-router";
import?HelloWorld?from?"../components/HelloWorld.vue";
const?routes:?Array<RouteRecordRaw>?=?[
????{
????????path:?"/",
????????name:?"HelloWorld",
????????component:?HelloWorld,
????},
????{
????????path:?"/about",
????????name:?"About",
????????//?route?level?code-splitting
????????//?this?generates?a?separate?chunk?(about.[hash].js)?for?this?route
????????//?which?is?lazy-loaded?when?the?route?is?visited.
????????component:?()?=>
????????????import(/*?webpackChunkName:?"About"?*/?"../components/About.vue")
????}
];
const?router?=?createRouter({
????history:?createWebHistory(process.env.BASE_URL),
????routes,
});
export?default?router;
再新建一个 components/About.vue 文件,内容如下:
<template>
??<img
????alt="Vue?logo"
????src="../assets/logo.png"
??/>
??<h1>{{?msg?}}</h1>
</template>
<script?lang="ts">
import?{?defineComponent?}?from?'vue'
export?default?defineComponent({
??name:?'About',
??data()?{
????return?{
??????msg:?'Hello?Vue?3.0?+?Vite!'
????}
??},
??setup()?{}
})
</script>
再修改 main.ts
import?{?createApp?}?from?'vue'
import?{?store,?key?}?from?'./store'
import?router?from?"./router";
import?App?from?'./App'
import?'./index.css'
const?app?=?createApp(App)
app.use(store,?key)
app.use(router)
app.mount('#app')
再访问 http://localhost:3000/
和 http://localhost:3000/about 即可
5. 加入 Element Plus
5.1 安装 element-plus
全局安装
npm?install?element-plus?--save
5.2 引入 Element Plus
你可以引入整个 Element Plus,或是根据需要仅引入部分组件。我们先介绍如何引入完整的 Element。
完整引入
在 main.js 中写入以下内容:
import?{?createApp?}?from?'vue'
import?ElementPlus?from?'element-plus';
import?router?from?"./router";
import?'element-plus/lib/theme-chalk/index.css';
import?App?from?'./App.vue';
import?'./index.css'
const?app?=?createApp(App)
app.use(ElementPlus)
app.use(router)
app.mount('#app')
以上代码便完成了 Element Plus 的引入。需要注意的是,样式文件需要单独引入。
按需引入
借助babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。
首先,安装 babel-plugin-component:
npm?install?babel-plugin-component?-D
然后,将 .babelrc 修改为:
{
??"plugins":?[
????[
??????"component",
??????{
????????"libraryName":?"element-plus",
????????"styleLibraryName":?"theme-chalk"
??????}
????]
??]
}
接下来,如果你只希望引入部分组件,比如 Button 和 Select,那么需要在 main.js 中写入以下内容:
import?{?createApp?}?from?'vue'
import?{?store,?key?}?from?'./store';
import?router?from?"./router";
import?{?ElButton,?ElSelect?}?from?'element-plus';
import?App?from?'./App.vue';
import?'./index.css'
const?app?=?createApp(App)
app.component(ElButton.name,?ElButton);
app.component(ElSelect.name,?ElSelect);
/*?or
?*?app.use(ElButton)
?*?app.use(ElSelect)
?*/
app.use(store,?key)
app.use(router)
app.mount('#app')
app.mount('#app')
更详细的安装方法请看 快速上手。
5.3 全局配置
在引入 Element Plus 时,可以传入一个全局配置对象。
该对象目前支持size
与zIndex
字段。size
用于改变组件的默认尺寸,zIndex
设置弹框的初始 z-index(默认值:2000)。按照引入 Element Plus 的方式,具体操作如下:
完整引入 Element:
import?{?createApp?}?from?'vue'
import?ElementPlus?from?'element-plus';
import?App?from?'./App.vue';
const?app?=?createApp(App)
app.use(ElementPlus,?{?size:?'small',?zIndex:?3000?});
按需引入 Element:
import?{?createApp?}?from?'vue'
import?{?ElButton?}?from?'element-plus';
import?App?from?'./App.vue';
const?app?=?createApp(App)
app.config.globalProperties.$ELEMENT?=?option
app.use(ElButton);
按照以上设置,项目中所有拥有size
属性的组件的默认尺寸均为 ‘small’,弹框的初始 z-index 为 3000。
最后
至此,一个基于 Vue3 全家桶 + Vite + TypeScript + Eslint + Element Plus 的开发环境已经搭建完毕,现在就可以编写代码了。
各个组件的使用方法请参阅它们各自的文档。
不得不说 Vue3 + Element Plus + Vite + TypeScript 是真的香!
推荐一个 Vue3 相关的资料汇总:Vue3 的学习教程汇总、源码解释项目、支持的 UI 组件库、优质实战项目,相信你会挖到矿哦!
Vue3 中文文档,国内 CDN 加速版:
https://vue3js.cn/docs/zh/
Element Plus 官网:
https://element-plus.org/#/zh-CN
作为 2021 第 2 篇原创技术文章,质量应该还可以吧,1 月的 KPI 完成,哈哈哈
猫哥的年终总结在这里:前端工程师的 2020 年终总结 - 乾坤未定,你我皆黑马,希望能带给你一点启发,也看看猫哥的脸都被打歪的
参考文章:vue3 + vite + typescript + eslint + jest 项目配置实践
推荐阅读