记录一下使用Vite创建Vue3+TS项目以及整合Element Plus框架,还有Less、Pinia、Vue-router、monaco-editor等插件或组件。
一、使用Vite创建Vue3+TS项目
第一步:在桌面新建一个temp文件夹,然后在VS Code打开,打开一个终端;
第二步:创建一个Vite项目
npm create vite@latest(1) 输入项目名,如: vue3_vite_ts_less_element_plus ,然后回车? Project name: » vue3_vite_ts_less_element_plus(2) 选择 Vue 框架,回车? Select a framework: » - Use arrow-keys. Return to submit.Vanilla> VueReactPreactLitSvelteOthers(3) 选择数据类型,回车? Select a variant: » - Use arrow-keys. Return to submit.JavaScript> TypeScriptCustomize with create-vue ↗Nuxt ↗(4) 创建完成,运行项目Done. Now run: cd vue3_vite_ts_less_element_plusnpm installnpm run devPS C:\Users\Administrator\Desktop\temp>
二、配置 @ 别名
第一步:修改 vite.config.ts 配置文件
修改前:
import { defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'// https://vitejs.dev/config/export default defineConfig({plugins: [vue()],})
修改后:
import { defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'import { resolve } from 'path'/*** 详情见 vitejs 文档:https://vitejs.dev/config/*/export default defineConfig({plugins: [vue()],resolve: {alias: {'@': resolve(__dirname, './src')}}})
第二步:修改 tsconfig.json 配置文件
修改前:
{"compilerOptions": {"target": "ESNext","useDefineForClassFields": true,"module": "ESNext","moduleResolution": "Node","strict": true,"jsx": "preserve","resolveJsonModule": true,"isolatedModules": true,"esModuleInterop": true,"lib": ["ESNext", "DOM"],"skipLibCheck": true,"noEmit": true},"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],"references": [{ "path": "./tsconfig.node.json" }]}
修改后:
{"compilerOptions": {"target": "ESNext","useDefineForClassFields": true,"module": "ESNext","moduleResolution": "Node","strict": true,"jsx": "preserve","resolveJsonModule": true,"isolatedModules": true,"esModuleInterop": true,"lib": ["ESNext", "DOM"],"skipLibCheck": true,"noEmit": true,"paths": {"@": ["src"],"@/*": ["src/*"]}},"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],"references": [{ "path": "./tsconfig.node.json" }]}
第三步:配置成功!
三、整合 Element Plus 框架
第一步:导入依赖包
npm i element-plus
第二步:在项目的 src 目录新建 plugins 文件夹,里面再新建 element-plus.ts 文件,写入以下代码
import ElementPlus from 'element-plus'import 'element-plus/theme-chalk/index.css'import zhCn from 'element-plus/es/locale/lang/zh-cn' // 汉化 element-plus 组件export default (app: any) => {app.use(ElementPlus, {locale: zhCn,})}
第三步:在项目的 main.ts 文件夹引入和使用该插件和注册图标,即整合完成,main.ts 文件如下所示
import { createApp } from 'vue'import App from './App.vue'import './global.less' // 全局样式const app = createApp(App)// 引入 ElementPlus 插件(npm i element-plus)import ElementPlusPlugin from '@/plugins/element-plus'// 全局注册 ElementPlus 图标组件(npm i @element-plus/icons-vue)import * as ElementPlusIcons from '@element-plus/icons-vue'for(const [key, component] of Object.entries(ElementPlusIcons)) {ponent(key, component)}app.use(ElementPlusPlugin).mount('#app')
第四步:验证整合成功,在项目的 App.vue 文件夹,例如写个按钮标签,保存即可看到效果,App.vue 文件如下所示
<template><el-buttonsize="small"type="primary"icon="UploadFilled"@click="void(0)">点击事件</el-button><el-button size="small" type="primary" plain @click="void(0)"><el-icon :size="18"><UploadFilled /></el-icon><span>点击事件</span></el-button><el-buttonsize="small"type="primary"circle><el-icon :size="18"><UploadFilled /></el-icon></el-button><el-icon:size="20"style="color: #5e7ce0; cursor: pointer"@click="void(0)"><UploadFilled /></el-icon></template><style lang="less">* {margin: 0;padding: 0;}html, body {width: 100%;height: 100%;margin: 0;padding: 0;border: none;}#app {width: 100%;height: 100%;font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;}</style>
四、整合 vue-router、pinia、less 等插件
第一步:查看vue-router所有版本,以及指定一个较新的版本来安装,使用方式和以前一致
npm view vue-router versions --jsonnpm i vue-router@4.1.0
第二步:安装pinia,听说Vuex拥抱ts没有Pinia好,详情使用方式见官网(Pinia 中文文档)
npm i pinia
在 src 目录新建 store 文件夹,再新建 index.ts 文件, 文件内容如下
import { createPinia } from 'pinia'const store = createPinia()export default store
再新建 ILoveYouStore 文件,文件内容如下
import { defineStore } from 'pinia'/*** 爱老虎油状态管理仓库*/export const ILoveYouStore = defineStore({id: 'ILoveYouStore', // ID必填且唯一state: () => {return {xxx: 'Hello,World!',yyy: 520,}},getters: {},actions: {setXxx(xxx: string) {this.xxx = xxx},}})
如下为在某个 vue 页面中,对 Pinia 的使用方式
<script>// 引入爱老虎油状态管理仓库import { ILoveYouStore } from '@/store/ILoveYouStore'const useILoveYouStore = ILoveYouStore()</script>然后随便用Vue2、Vue3、Vue3+语法糖来定义数据<!-- ^ Vue2 --><template><div v-if="useILoveYouStore.$state.xxx != null">{{ useILoveYouStore.$state.xxx }}</div><div v-else>{{ useILoveYouStore.$state }}</div></template><script>export default {data: () => ({useILoveYouStore: useILoveYouStore,}),}</script><!-- / Vue2 --><!-- ^ Vue3 --><script>import { ref } from 'vue';export default {setup() {const useILoveYouStore = useILoveYouStorereturn { useILoveYouStore }},}</script><!-- / Vue3 --><!-- ^ Vue3+语法糖 --><script setup>const useILoveYouStore = useILoveYouStore</script><!-- / Vue3+语法糖 -->
第三步:安装less/scss,看个人使用习惯来安装
npm i lessnpm i scss
第四步、其他插件的整合也差不多的,再来个封装使用Axios插件
使用Vue Cli创建Vue3+TS项目并整合Element Plus框架以及封装使用Axios插件_帅龍之龍的博客-CSDN博客
五、整合微软在线代码编辑器 monaco-editor 插件,该插件能够轻松实现,在线浏览仅一个页面就超过30万行代码或日志,快速渲染高亮文本却不卡的功能
第一步:查看 monaco-editor 版本
npm view monaco-editor versions --json
第二步:安装指定版本的 monaco-editor
npm i monaco-editor@0.33.0
第三步:将 App.vue 改为以下代码
<template><div class="m-e" id="m-e-id"><div class="m-e-main"><div class="m-e-main_toolbar" :style="isThemeLightOrBlack ? 'background-color: #fff; box-shadow: 0px 2px 5px #ddd;' : 'background-color: #1e1e1e; box-shadow: 0px 2px 5px #111;'"><div class="m-e-main_toolbar_left"><span>日志 - {{ title }}</span></div><div class="m-e-main_toolbar_right" :style="isThemeLightOrBlack ? 'color: #000' : 'color: #fff'"><a title="查找" @click="findByKeyword"><i class="fa fa-search"/></a><a title="回到顶部" @click="scrollToTop"><i class="fa fa-chevron-circle-up"/></a><a title="回到底部" @click="scrollToBottom"><i class="fa fa-chevron-circle-down"/></a><a title="是否截断换行" @click="setEditorWordWrap"><i class="fa fa-bars"/></a><a title="切换白天或暗夜模式" @click="setEditorTheme"><i class="fa fa-adjust"/></a><a :title="fullScreen ? '退出全屏' : '全屏显示'" @click="handleFullScreenClick"><i :class="fullScreen ? 'fa fa-compress' : 'fa fa-expand'"/></a><a title="下载日志" @click="handleDownloadLogClick"><i class="fa fa-cloud-download" style="position: relative; top: 0px"/></a></div></div><div :id="id" class="m-e-main_container" :style="'height: calc(100% - 40px)'"></div></div></div></template><script>// 引入获取原始数据组件import { toRaw } from 'vue'// 引用 font-awesome 资源(npm i font-awesome)import 'font-awesome/css/font-awesome.min.css';// 引入 monaco-editor 组件import * as me from 'monaco-editor'export default {data: () => ({editor: null,// 编辑器对象id: null,// 编辑器DOM节点IDtitle: '',// 编辑器标题content: '',// 编辑器内容height: 'auto',// 编辑器高度readOnly: false,// 编辑器是否禁用isScrollToBottom: false, // 是否滚动到底部// 其他配置项...fullScreen: false,// 是否全屏状态wordWrap: false,// 当单行文本太长时截断换行,true 为换行,false 为不换行isThemeLightOrBlack: false,// 明亮或暗夜模式,true 为白天模式,false 为暗夜模式}),mounted() {this.newME()/*** 监听全屏显示状态*/let that = this;window.onresize = function() {if (!document.fullscreenElement) {that.fullScreen = false;} else {that.fullScreen = true;} }},watch: {},methods: {/** */newME() {this.id = 'me_czq' // 随便起一个DOM节点ID名称this.title = '帅龍之龍' // 随便起一个编辑器标题this.content = 'Hello,World!' // 随便写入一点编辑器内容this.initMonacoEditor(this.id, this.content, this.readOnly)},/*** 实例化在线代码编辑器* * 文档地址:https://microsoft.github.io/monaco-editor/api/index.html*/async initMonacoEditor(id, content, readOnly) {try {// 异步获取节点,确保 Dom 节点已经渲染完成,不可删await document.getElementById(this.id);this.editor = me.editor.create(document.getElementById(id), {value: content,// 编辑器内容language: 'python',// 选择支持语言automaticLayout: true,// 是否自动布局theme: 'vs-dark',// 官方自带三种主题:vs、hc-black、vs-darkreadOnly: readOnly,// 设置是否只读wordWrap: this.wordWrap ? 'on' : 'off',// 设置启用截断功能scrollBeyondLastLine: false,// 滚动完最后一行后再滚动一屏幕// 滚动条// scrollbar: {// verticalScrollbarSize: 15,// horizontalScrollbarSize: 15// },// 是否开启小地图minimap: {enabled: true},});} catch (e) {console.error(e)}// 设置编辑器滚动到最底部// this.scrollToBottom();},/*** 设置编辑器的内容且滚动到最底部*/setEditorContent(val) {toRaw(this.editor).setValue(val);this.scrollToBottom();},/*** 获取编辑器的内容*/getEditorContent() {toRaw(this.editor).getValue();},/*** 打开编辑器查找功能*/findByKeyword() {try {// 先聚焦编辑器toRaw(this.editor).focus();// 从模型中获取要查找的字符串范围 new Range(startLineNumber, startColumn, endLineNumber, endColumn)toRaw(this.editor).setSelection(new me.Range(1, 9999, 1, 10000));// 触发查找操作// toRaw(this.editor).getAction('actions.find').run();// 查找方式一toRaw(this.editor).trigger('', 'actions.find');// 查找方式二} catch(error) {console.log(error);}},/*** 设置编辑器从只读变成可写*/setEditorRW() {toRaw(this.editor).updateOptions({readOnly: false});},/*** 设置编辑器开关截断功能*/setEditorWordWrap() {this.wordWrap = this.wordWrap ? false : true;if (this.wordWrap) {toRaw(this.editor).updateOptions({wordWrap: 'on'});} else {toRaw(this.editor).updateOptions({wordWrap: 'off'});}},/*** 设置编辑器明亮或暗夜模式*/setEditorTheme() {this.isThemeLightOrBlack = this.isThemeLightOrBlack ? false : true;if (this.isThemeLightOrBlack) {toRaw(this.editor).updateOptions({theme: 'vs'});} else {toRaw(this.editor).updateOptions({theme: 'vs-dark'});}},/*** 设置编辑器滚动到最顶部*/scrollToTop() {toRaw(this.editor).setScrollPosition({scrollTop: 0});},/*** 设置编辑器滚动到最底部*/scrollToBottom() {toRaw(this.editor).revealLine(toRaw(this.editor).getModel().getLineCount());},/*** 全屏显示句柄*/handleFullScreenClick () {const element = document.getElementById('m-e-id');if (!document.fullscreenElement) {element.requestFullscreen();} else {document.exitFullscreen();} },/*** 下载日志句柄*/handleDownloadLogClick() {this.exportFile(this.title, this.content);},/*** 下载日志*/exportFile(name, data) {let url = window.URL || window.webkitURL || window;let blob = new Blob([data]);let event = document.createEvent("MouseEvents");event.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);let link = document.createElementNS("/1999/xhtml", "a");link.href = url.createObjectURL(blob);link.download = name;link.dispatchEvent(event);}},/*** 销毁在线代码编辑器*/beforeDestroy() {if (toRaw(this.editor)) {toRaw(this.editor).dispose()}},}</script><style lang="less" scoped>.m-e {width: 100%;height: 100%;.m-e-main {width: 100%;height: 100%;.m-e-main_toolbar {width: 100%;height: 40px;box-shadow: 0px 2px 5px #000;display: flex;position: relative;z-index: 99;.m-e-main_toolbar_left {flex: 1;overflow: hidden;span {color: #fff;display: block;font-size: 15px;padding-left: 10px;line-height: 26px;line-height: 40px;white-space:nowrap;/* 不换行 */overflow:hidden;/* 内容超出宽度时隐藏超出部分的内容 */text-overflow:ellipsis;/* 当对象内文本溢出时显示省略标记(...) ;需与overflow:hidden;一起使用。*/// user-select: none;}}.m-e-main_toolbar_right {margin-right: 15px;display: flex;a {width: 16px;height: 16px;line-height: 16px;transition: ease all 0.3s ;text-align: center;display: inline-block;padding: 5px;cursor: pointer;border-radius: 2px;margin: 7px 0 7px 5px;i {font-size: 15px;}&:hover {background-color: rgba(255, 255, 255, 0.1);}}}}}}</style>
六、配置服务端接口地址
第一步:在 vite.config.ts 文件增加server 配置,完整内容如下所示。
import { defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'import { resolve } from 'path'/*** 详情见 vitejs 文档:https://vitejs.dev/config/*/export default defineConfig({plugins: [vue()],base: '/xxx/', // 配置相对地址或绝对地址,此处应为绝对地址,若将 Web 部署到 Nginx 所在的目录为 nginx-1.17.8/html/xxx ,则这个 base 的值就为 /xxx/resolve: {alias: {'@': resolve(__dirname, './src'),assets: resolve(__dirname, './src/assets'),}},server: {host: '', // 主机port: 5173, // 端口proxy: {// 项目 v1 的服务端接口地址'/v1/api': {target: 'http://127.0.0.1:8091/',changeOrigin: true,secure: false,ws: true},// 项目 v2 的服务端接口地址'/v2/api': {target: 'http://127.0.0.1:8092/',changeOrigin: true,secure: false,ws: true},// 项目 v3 的服务端接口地址'/v3/api': {target: 'http://127.0.0.1:8093/',changeOrigin: true,secure: false,ws: true},// // 默认服务端接口地址// '/': {// target: 'http://127.0.0.1:8090/',// changeOrigin: true,// secure: false,// ws: false// }}}})
Tip:如何降低 vite 版本?
第一步:删除项目中的 node_modules 目录
第二步:删除项目中的 package-lock.json 文件
第三步:安装指定版本的 vite
npm i vite@3.0.0 -D
第四步:安装指定版本的 @vitejs/plugin-vue
npm i @vitejs/plugin-vue@3.0.0 -D
第五步:重新执行导入依赖指令,若出现两个vite版本的报错,重复步骤一和步骤二后,再重新导入依赖
npm i
第六步:启动项目,运行正常
npm run dev
报错问题总结
问题一:找不到名称“__dirname”。
原因:path 模块是 node.js 的内置模块,而 node.js 默认不支持 ts 文件的
解决:安装 @type/node 依赖包 npm install @types/node --save-dev
vue3+vite+ts 配置@时vscode报找不到__dirname的问题_vite __dirname_yuhaiyang11的博客-CSDN博客
问题二:未设置 "baseUrl" 时,不允许使用非相对路径。是否忘记了前导 "./"?。
解决:在tsconfig.json 文件添加baseUrl 配置
{"compilerOptions": {..."baseUrl": ".", // 未设置 "baseUrl" 时,不允许使用非相对路径。"paths": {"@": ["src"],"@/*": ["src/*"]}},...}
问题三:找不到模块“./App.vue”或其相应的类型声明。
解决:在src目录新建shims-vue.d.ts文件,文件内容为以下代码
/* eslint-disable */declare module '*.vue' {import type { DefineComponent } from 'vue'const component: DefineComponent<{}, {}, any>export default component}
问题四:Vite项目如何配置相对地址或绝对地址
解决:在 vite.config.ts 文件中加上 base 属性,值可以为相对地址'./',也可以为绝对地址'/xxx/'
export default defineConfig({plugins: [vue()],base: '/xxx/', // 配置相对地址或绝对地址,此处应为绝对地址,若将 Web 部署到 Nginx 所在的目录为 nginx-1.17.8/html/xxx ,则这个 base 的值就为 /xxx/resolve: {alias: {'@': resolve(__dirname, './src'),assets: resolve(__dirname, './src/assets'),}},})
问题五:当 npm run build 打包时,报错,提示信息为 Did you mean to enable the 'allowJs' option?
解决:在tsconfig.json 文件增加 allowJs 配置
{"compilerOptions": {"allowJs": true, // xxx.vue is a JavaScript file. Did you mean to enable the 'allowJs' option?// ...}}
问题六:因项目未指定 ESlint 解析器,导致一些语法解析错误
解决:新建 .eslintrc.js 文件,注意文件名开头有个点,然后就完美解决
module.exports = {env: {browser: true,es: true,node: true,},extends: ["plugin:vue/vue3-recommended", "plugin:prettier/recommended"],parserOptions: {ecmaVersion: "latest",parser: "@typescript-eslint/parser", // 指定ESlint的解析器sourceType: "module",},plugins: ["vue", "@typescript-eslint", "prettier"],rules: {"prettier/prettier": "error",},}
问题七:the >>> and /deep/ combinators have been deprecated. Use :deep() instead.
解决:/deep/ 替换为 :deep()
修改前:/deep/ .el-table {// ...}修改后::deep(.el-table) {// ...}
项目地址
vue3_vite_ts_less_element_plus: 这是一个由Vite+Vue3构建的项目,整合了TS+Less+Element Plus+Pinia+iconic等框架或插件的示例项目,仅供学习参考。