从头构建vue3.0+ts+vite框架

前言

框架搭建是独当一面的基础:
	本文回顾基于vite+vue3.0+ts框架,我会尽量讲的更全更细节,同时方便以后复用

vite环境搭建,构建vite-vue-ts项目

  1. 安装vite环境
    	npm init @vitejs/app
    	或者
    	yarn create @vitejs/app
    
  2. 使用vite初始化vite+vue+ts的项目
    	npm init @vitejs/app vite-project
    	或者
    	yarn create @vitejs/app vite-project
    
  3. 选择项目类型
    在这里插入图片描述
    在这里插入图片描述
    	cd vite-project
    
    在这里插入图片描述
    需要进行安装包
    npm install
    安装成功后进行
    yarn dev
    
    在这里插入图片描述
    在这里插入图片描述
    至此项目完成了基础的初始化
    

项目配置

  1. 路由配置

    	安装vue-router
    	npm install vue-router@4
    	或者
    	yarn add vue-router@4
    

    在src下新建一个router文件夹,作为vue-router的配置目录。此目录下再新建index.ts文件,编辑内容如下:

    import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
    const history = createWebHistory()
    const routes: Array<RouteRecordRaw> = [
      {
        path: '/',
        redirect: '/home',
      },
      {
        path: '/home',
        name: 'home',
        component: () => import('@/views/home/index.vue'),
      },
    ];
    const router = createRouter({
      history,
      routes,
    })
    export default router
    

    新建一个views文件夹,作为项目界面开发目录。参考router中的配置可知,在views目录下新建home目录并新建index.vue,编辑文件如下:

    <template>
      <h2>{{ msg }}</h2>
      <h2>{{ count }}</h2>
    </template>
    <script setup lang="ts">
    import { ref } from 'vue'
    
    const msg = ref('Hello')
    const count = ref(710)
    </script>
    
    <style scoped>
    </style>
    

    在main.ts中引入vue-router

    	import { createApp } from 'vue'
    	import App from './App.vue';
    	import router from './router';
    	
    	createApp(App)
    	    .use(router)
    	    .mount('#app')
    

    在App.vue中使用vue-router

    	<template>
    	  <router-view />
    	</template>
    	
    	<script setup lang="ts">
    	</script>
    	
    	<style>
    	#app {
    	  font-family: Avenir, Helvetica, Arial, sans-serif;
    	  -webkit-font-smoothing: antialiased;
    	  -moz-osx-font-smoothing: grayscale;
    	  text-align: center;
    	  color: #2c3e50;
    	}
    	</style>
    

    这个时候页面报错
    在这里插入图片描述
    无法解析@符号
    安装一个path的插件:
    npm install --save-dev @types/node
    然后对vite.config.ts 进行修改
    修改 vite.config.ts 文件:

    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    
    /************************************* 路径配置 start ********************************/
    import { resolve } from 'path' 
    
    const pathResolve = (dir: string): any => {  
      return resolve(__dirname, ".", dir)          
    }
    
    const alias: Record<string, string> = {
      '@': pathResolve("src")
    }
    /************************************* 路径配置 end ********************************/
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [vue()],
      resolve: {  // ****************** 路径配置新增
        alias     // ****************** 路径配置新增
      }           // ****************** 路径配置新增
    })
    

    在这里插入图片描述
    在tsconfig.node.json添加 compilerOptions 对象属性添加 “allowSyntheticDefaultImports”: true 即可 在这里插入图片描述

    重新启动
    在这里插入图片描述

  2. vuex 配置
    安装vuex

    	npm install vuex@next --save
    	或者
    	yarn add vuex@next --save
    	同时安装 vuex-persist 持久化存储⽽⽣的⼀个插件
    	npm install --save vuex-persist
    	or
    	yarn add vuex-persist
    

    在 src目录下创建一个store文件夹,在里面新建 index.ts、module
    编辑index.ts如下:

    	import { createStore } from 'vuex';
    	import VuexPersistence from 'vuex-persist';
    	
    	const persistedState = new VuexPersistence({ // 数据持久化
    	  storage: window.sessionStorage,
    	  modules: ['keyword'],
    	});
    	
    	const store = createStore({
    	  plugins: [persistedState.plugin],
    	  modules: {
    	  },
    	});
    	
    	export default store;
    

    在main.ts中引入

    	import { createApp } from 'vue'
    	import App from './App.vue';
    	import router from './router';
    	import store from '@/store';
    	
    	createApp(App)
    	    .use(router)
    	    .use(store)
    	    .mount('#app')
    

    出现错误
    在这里插入图片描述
    ts 配置需要读取项目根路径的 tsconfig.json,添加 paths 配置即可:

    	{
      "compilerOptions": {
        "target": "esnext",
        "useDefineForClassFields": true,
        "module": "esnext",
        "moduleResolution": "node",
        "strict": true,
        "jsx": "preserve",
        "sourceMap": true,
        "resolveJsonModule": true,
        "esModuleInterop": true,
        "lib": ["esnext", "dom"],
        "paths": {
          "@/*": [
            "./src/*"
          ]
        }
      },
      "include": [
        "src/**/*.ts",
        "src/**/*.d.ts",
        "src/**/*.tsx",
        "src/**/*.vue"
      ]
    }
    
  3. css语言 scss

    	npm install --save-dev sass-loader
    	npm install --save-dev node-sass
    	npm install --save-dev sass
    

    成功
    在这里插入图片描述

  4. 全局引入element-plus

    	安装:
    	npm install element-plus
    
    	import { createApp } from 'vue'
    	import App from './App.vue';
    	import router from '@/router';
    	import store from '@/store';
    	import ElementPlus from 'element-plus'
    	import 'element-plus/dist/index.css'
    	
    	createApp(App)
    	    .use(router)
    	    .use(store)
    	    .use(ElementPlus)
    	    .mount('#app')
    
  5. 按需导入element

    	自动导入:安装插件
    	npm install -D unplugin-vue-components unplugin-auto-import
    
    // vite.config.ts
    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    import AutoImport from 'unplugin-auto-import/vite'
    import Components from 'unplugin-vue-components/vite'
    import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
    import path from 'path'
    const { resolve } = require('path')
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [
        vue(),
        AutoImport({
          resolvers: [ElementPlusResolver()],
        }),
        Components({
          resolvers: [ElementPlusResolver()],
        }),
      ],  // 注册插件
      server: {
        open: true
      },
      resolve: {
        alias: {
          '@': resolve(__dirname, './src'),
        },
      }
    })
    

    这时页面多了 两个文件:页面使用elment标签就会自动导入
    在这里插入图片描述

  6. 集成Axios

    	安装:npm install axios
    
    	配置接口proxy代理:
    	代理我们可以使用npm 官方文档推荐的dotenv 用于动态获取.env 文件加载到 process.env 
    	安装
    	npm install dotenv
    

    根目录下创建两个 .env 文件:.env.development(开发环境) .env.production(生产环境)

    	// .env.development 开发环境的代理配置
    	VITE_PUBLIC_PATH='./'
    	VITE_BASE_API='/asr'
    	VITE_TARGET_HOST='http://192.168.0.222:58008'
    
    	// .env.production
    	VITE_PUBLIC_PATH='/'
    	VITE_BASE_API='/asr'
    

    修改 vite.config.ts

    	import { defineConfig, UserConfig } from 'vite'
    	import vue from '@vitejs/plugin-vue'
    	import AutoImport from 'unplugin-auto-import/vite'
    	import Components from 'unplugin-vue-components/vite'
    	import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
    	import path from 'path'
    	// @ts-ignore
    	import fs from 'fs'
    	// @ts-ignore
    	import dotenv from 'dotenv'
    	
    	const { resolve } = require('path')
    	
    	// https://vitejs.dev/config/
    	export default defineConfig(({ mode }: UserConfig): UserConfig => {
    	  // 根据环境变量加载环境变量文件
    	  const ASR_ENV = dotenv.parse(fs.readFileSync(`.env.${mode}`))
    	  return {
    	    base: ASR_ENV.VITE_PUBLIC_PATH,
    	    server: {
    	      host: '0.0.0.0',
    	      port: 3000,
    	      https: false,
    	      proxy: {
    	        [ASR_ENV.VITE_BASE_API]: {
    	          target: `${ASR_ENV.VITE_TARGET_HOST}`,
    	          changeOrigin: true,
    	        },
    	      },
    	    },
    	    resolve: {
    	      alias: {
    	        '@': resolve(__dirname, './src'),
    	      },
    	    },
    	    plugins: [
    	      vue(),
    	      AutoImport({
    	        resolvers: [ElementPlusResolver()],
    	      }),
    	      Components({
    	        resolvers: [ElementPlusResolver()],
    	      }),
    	    ],
    	    css: {
    	      preprocessorOptions: {
    	        scss: {
    	          charset: false,
    	        },
    	      },
    	    },
    	    build: {
    	      minify: 'terser', // 是否进行压缩,boolean | 'terser' | 'esbuild',默认使用esbuild
    	      // reportCompressedSize: true,
    	      manifest: false, // 是否产出maifest.json
    	      sourcemap: false, // 是否产出soucemap.json
    	      chunkSizeWarningLimit: 1500,
    	    },
    	  }
    	})
    

    封装axios
    用到的插件:npm i js-cookie
    在src下新建utils文件夹:
    在这里插入图片描述

    	// auth.ts
    	// @ts-ignore
    	import Cookies from 'js-cookie';
    	
    	const TokenKey = 'asr-token';
    	
    	export const getToken = () => Cookies.get(TokenKey);
    	
    	export const delToken = () => Cookies.remove(TokenKey);
    
    	// request.ts
    	import axios from 'axios'; // 引入axios
    	import Vrouter from '@/router'
    	import { getToken } from '@/utils/auth';
    	const Router = Vrouter;
    	console.log('import.meta.env.VITE_BASE_API', import.meta.env.VITE_BASE_API)
    	const service = axios.create({
    	  baseURL: import.meta.env.VITE_BASE_API as string,
    	  timeout: 99999,
    	});
    	// http request 拦截器
    	service.interceptors.request.use(
    	  (config:any) => {
    	    // 全局添加 token
    	    if (getToken()) {
    	      config.headers['asr-token'] = getToken();
    	    }
    	    return config;
    	  },
    	  (error) => {
    	    console.error(error);
    	    return Promise.reject(error);
    	  },
    	);
    	// http response 拦截器
    	service.interceptors.response.use(
    	  (response) => {
    	    if (response.data.code === 9) {
    	      // Router.replace('/rejectUser');
    	      return
    	    }
    	    return response.data
    	  },
    	  (error) => {
    	    if (error.response && error.response.status && error.response.status === 403) {
    	    //   logout().then(() => {
    	    //     // removeToken()
    	    //   });
    	    }
    	    // 网络超时
    	    if (error.message && error.message.includes('timeout')) {
    	      console.error('请求超时');
    	      return error.message;
    	    }
    	    if (error.response && error.response.status && error.response.status === 500) {
    	      // 没有权限
    	      console.error('接口异常');
    	      return error;
    	    }
    	    return error;
    	  },
    	);
    	export default service;
    

    src下新建types类型文件夹:用于声明类型
    在这里插入图片描述
    /src/types/service/index.ts

    	interface resModel {
    	    code:number
    	    msg:string
    	    data:any
    	    [propname:string]:any
    	  }
    	
    	export interface requestModel {
    	    <T>(data?: T): Promise<resModel>
    	 }
    

    src/types/service/shims.d.ts

    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    import axios from 'axios';
    
    declare module 'axios' {
      export interface AxiosInstance {
        <T = any>(config: AxiosRequestConfig): Promise<T>;
        request<T = any> (config: AxiosRequestConfig): Promise<T>;
        get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
        delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
        head<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
        post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
        put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
        patch<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
      }
    }
    

    src下新建api文件夹用于接口API二次封装
    在这里插入图片描述
    使用示例
    src/api/user.ts

    import request from '@/utils/request';
    import { requestModel } from '@/types/service';
    
    // 获取用户信息
    export const getUserInfo: requestModel = () => request({
      url: '/info',
      method: 'get',
    });
    
    // 退出登录
    export const logout: requestModel = () => request({
      url: '/quit',
      method: 'post',
    });
    
  7. 配置eslint

    	yarn add eslint@7.2.0 eslint-plugin-vue@7.20.0 vue-eslint-parser @typescript-eslint/parser @typescript-eslint/eslint-plugin@4.33.0 eslint-config-airbnb-base@15.0.0 eslint-plugin-import@2.25.4 -D
    

    根目录设置.eslintrc.js

    module.exports = {
      root: true,
      globals: {
        defineEmits: 'readonly',
        defineProps: 'readonly',
      },
      extends: [
        'plugin:@typescript-eslint/recommended',
        'plugin:vue/vue3-recommended',
        'airbnb-base',
      ],
      parserOptions: {
        parser: '@typescript-eslint/parser',
        ecmaVersion: 2020,
      },
      rules: {
        'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 禁用 debugger
        'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 禁用 console
        'no-bitwise': 'off', // 禁用按位运算符
        'no-tabs': 'off', // 禁用 tab
        'array-element-newline': ['error', 'consistent'], // 强制数组元素间出现换行
        indent: [
          'error',
          2,
          { MemberExpression: 0, SwitchCase: 1, ignoredNodes: ['TemplateLiteral'] },
        ], // 强制使用一致的缩进
        quotes: ['error', 'single'], // 强制使用一致的反勾号、双引号或单引号
        'comma-dangle': ['error', 'always-multiline'], // 要求或禁止末尾逗号
        'object-curly-spacing': ['error', 'always'], // 强制在大括号中使用一致的空格
        'max-len': ['error', 120], // 强制一行的最大长度
        'no-new': 'off', // 禁止使用 new 以避免产生副作用
        'linebreak-style': 'off', // 强制使用一致的换行风格
        'import/extensions': 'off', // 确保在导入路径中统一使用文件扩展名
        'eol-last': 'off', // 要求或禁止文件末尾存在空行
        'no-shadow': 'off', // 禁止变量声明与外层作用域的变量同名
        'no-unused-vars': 'warn', // 禁止出现未使用过的变量
        'import/no-cycle': 'off', // 禁止一个模块导入一个有依赖路径的模块回到自己身上
        'arrow-parens': 'off', // 要求箭头函数的参数使用圆括号
        semi: ['error', 'never'], // 要求或禁止使用分号代替 ASI
        // semi:0, // 取消对分号校验
        eqeqeq: 'off', // 要求使用 === 和 !==
        'no-param-reassign': 'off', // 禁止对 function 的参数进行重新赋值
        'import/prefer-default-export': 'off', // 如果模块只输入一个名字,则倾向于默认输出
        'no-use-before-define': 'off', // 禁止在变量定义之前使用它们,则倾向于默认输出
        'no-continue': 'off', // 禁用 continue 语句
        'prefer-destructuring': 'off', // 优先使用数组和对象解构
        'no-plusplus': 'off', // 禁用一元操作符 ++ 和 --
        'prefer-const': 'warn', // 要求使用 const 声明那些声明后不再被修改的变量
        'global-require': 'off', // 要求 require() 出现在顶层模块作用域中
        'no-prototype-builtins': 'off', // 禁止直接调用 Object.prototypes 的内置属性
        'consistent-return': 'off', // 要求 return 语句要么总是指定返回的值,要么不指定
        'one-var-declaration-per-line': 'off', // 要求或禁止在变量声明周围换行
        'one-var': 'off', // 强制函数中的变量要么一起声明要么分开声明
        'import/named': 'off', // 确保命名导入与远程文件中的命名导出相对应
        'object-curly-newline': 'off', // 强制大括号内换行符的一致性
        'default-case': 'off', // 要求 switch 语句中有 default 分支
        'no-trailing-spaces': 'off', // 禁用行尾空格
        'func-names': 'off', // 要求或禁止使用命名的 function 表达式
        radix: 'off', // 强制在 parseInt() 使用基数参数
        'no-unused-expressions': 'off', // 禁止出现未使用过的表达式
        'no-underscore-dangle': 'off', // 禁止标识符中有悬空下划线
        'no-nested-ternary': 'off', // 禁用嵌套的三元表达式
        'no-restricted-syntax': 'off', // 禁用特定的语法
        'no-await-in-loop': 'off', // 禁止在循环中出现 await
        'import/no-extraneous-dependencies': 'off', // 禁止使用外部包
        'import/no-unresolved': 'off', // 确保导入指向一个可以解析的文件/模块
        'template-curly-spacing': ['error', 'always'], // 要求或禁止模板字符串中的嵌入表达式周围空格的使用
        '@typescript-eslint/no-var-requires': 'off', // 除import语句外,禁止使用require语句
        '@typescript-eslint/no-empty-function': 'off', // 不允许空函数
        '@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
        'guard-for-in': 'off', // 要求 for-in 循环中有一个 if 语句
        'class-methods-use-this': 'off', // 强制类方法使用 this
        'vue/html-indent': ['error', 2], // 在<template>中强制一致缩进
        'vue/html-self-closing': 'off', // 执行自闭合的风格
        'vue/max-attributes-per-line': [ // 强制每行属性的最大数量
          'warn',
          {
            singleline: {
              max: 3,
              allowFirstLine: true,
            },
            multiline: {
              max: 1,
              allowFirstLine: false,
            },
          },
        ],
        'vue/singleline-html-element-content-newline': 'off', // 要求单行元素的内容前后有一个换行符
      },
    }
    

在这里插入图片描述

shift + command + p 组合键打开命令面板,输入 settings 回车打开配置文件。
js { "workbench.iconTheme": "vscode-icons", "workbench.colorTheme": "Default Dark+", "vsicons.dontShowNewVersionMessage": true, "eslint.validate": [ "javascript", "javascriptreact", "vue", "typescript" ], "eslint.format.enable": true, "eslint.alwaysShowStatus": true, "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, "files.associations": { "*.vue": "vue" }, }
直接 control + s 键保存,VSCode 会自动修复代码 ESLint 检测出的错误,帮助我们去除了 ; 逗号。

  1. 配置rem适配布局

     	1、根据页面屏幕大小计算每个页面的基准值,即一个rem为多少px
    

    src目录下创建rem.ts

    	// 基准大小
       const baseSize = 16
       // 设置 rem 函数
       function setRem() {
         // 当前页面宽度相对于 750 宽的缩放比例,可根据自己需要修改。
         const scale = document.documentElement.clientWidth / 1920
         // 设置页面根节点字体大小
         document.documentElement.style.fontSize = `${baseSize * Math.min(scale, 2)}px`
       }
       // 初始化
       setRem()
       // 改变窗口大小时重新设置 rem
       window.onresize = () => {
         setRem()
       }
       ```
    
    
    注意:如果提示 “无法在 "--isolatedModules" 下编译“rem.ts”,因为它被视为全局脚
    本文件。请添加导入、导出或空的 "export {}" 语句来使它成为模块 ”此时你应该在 
    tsconfig.json 文件中将 isolatedModules 字段设置为 false。
    
    
    

在main.ts中引入:

	 import './rem'

安装依赖
npm install postcss-pxtorem -D
对vite.config.ts文件添加配置

	css: {
         preprocessorOptions: {
           scss: {
             charset: false,
           },
         },
   +      postcss: {
   +       plugins: [
   +          postCssPxToRem({
   +            rootValue: 16, // 1rem的大小
   +            propList: ['*'], // 需要转换的属性,这里选择全部都进行转换
   +          }),
   +       ],
   +      },
       },
结束
  • 9
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Vue 3.0是一个非常流行的JavaScript框架,不仅易于学习和使用,而且可以与许多UI框架集成。ElementUI是一种流行的UI框架,提供了许多易于使用的UI组件和效果。在Vue 3.0中,可以使用TypeScriptTS)编写代码,提供了更好的类型安全和代码可读性。下面是在Vue 3.0中引用ElementUI的步骤: 1. 安装ElementUI:可以使用npm或yarn命令安装ElementUI ``` npm i element-plus -S ``` 2. 使用TypeScript的话需要安装依赖 `ts` 和 `webpack`(如果没有的话) ``` npm i webpack webpack-cli webpack-dev-server typescript ts-loader -D ``` 3. 在Vue项目中引入ElementUI样式和组件: 3.1 引入样式(会自动挂载到全局样式表上) ```scss // main.ts import 'element-plus/dist/index.css' ``` 3.2 引入组件 ```js // main.ts or other entry file import { createApp } from 'vue' import App from './App.vue' import ElementPlus from 'element-plus' import 'element-plus/styles/index.css' // 引入组件样式 const app = createApp(App) app.use(ElementPlus) // 注册全局组件 app.mount('#app') ``` 这样就可以通过引入ElementPlus来使用ElementUI组件了。例如,在Vue 3.0中使用一个按钮组件: ```vue <template> <el-button type="primary">click me</el-button> </template> <script lang="ts"> import { defineComponent } from 'vue' import { ElButton } from 'element-plus' export default defineComponent({ name: 'MyButton', components: { ElButton } // 局部注册组件 }) </script> ``` 总的来说,引用ElementUI到Vue 3.0中相对比较简单,只需要安装依赖与组件后进行注册即可正常使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值