• vite2+Vue3+elementPlus+eslint


    开始

    vite2新型前端构建工具,能够显著提升前端开发体验,话不多说,我们先来体验一下

    搭建vite项目

    Vite 需要 Node.js 版本 >= 12.0.0。

    # NPM
    npm init @vitejs/app
    
    # YARN 
    yarn create @vitejs/app
    


    然后按照操作,选择你想要的模板执行就行。

    我们可以通过附加的命令行选项直接指定项目名称和你想要使用的模板,可以直接生成项目

    # 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
    

    配置项目

    首先看下项目结构:

    # my-vue-app
    
    ├── index.html
    ├── package.json
    ├── public
    │   └── favicon.ico
    ├── src
    │   ├── App.vue
    │   ├── assets
    │   │   └── logo.png
    │   ├── components
    │   │   └── HelloWorld.vue
    │   └── main.js
    ├── tree.md
    └── vite.config.js
    

    打开项目,我们看到结构还是cli4结构类似的,就是简单了好多了。

    vite2现在还没有开箱即用的模板,供我们使用,不过文档还是比较全面的。vite中文文档

    下面我们配置下:

    1. vue-router

     # vue-router4.0正式版已经发布,我们使用4.0版本
     # 如果你想下载最新版本 yarn add vue-router@4. 会让你选择4.0所有版本,你选择想要的版本即可
    
     # NPM
     npm install vue-router@4.0.4
    
     # YARN
     yarn add vue-router@4.0.4
    
    1. 在src创建router文件夹,新建index.js文件
     import { createRouter, createWebHashHistory } from 'vue-router'
     import Home from '../views/Home.vue'
    
     const routes = [
       {
         path: '/',
         name: 'Home',
         component: Home
       },
       {
         path: '/about',
         name: 'About',
         component: () => import('@/views/About.vue') // @/views设置的别名
       }
     ]
    
     const router = createRouter({
       history: createWebHashHistory(import.meta.env.BASE_URL),
       routes
     })
    
     export default router
    
    
    2. 在main.js引入router
    import { createApp } from 'vue'
    import router from './router'
    import App from './App.vue'
    
    createApp(App).use(router).mount('#app')
    
    3. 修改App.vue文件
    <template>
      <router-view />
    </template>
    
    <script setup>
    </script>
    
    <style></style>         
    
    4. src添加Home.vue
    <template>
      <router-link to="/">
        Home
      </router-link>
      <router-link to="/about">
        About
      </router-link>
    </template>
    
    <script>
    export default {
    
    }
    </script>
    
    5. src添加About.vue
    //  About.vue
    <template>
      <div>About</div>
    </template>
    
    <script>
    export default {
    
    }
    </script>
    
    <style></style>
    
    

    在链接中输入http://localhost:8000/#/about 内容显示about,那么恭喜你已经配置成功了。

    6. 模块化

    如果你想把项目模块化,可以按照下面的结构和方式配置(vuex类似),如果不是,请跳过此步骤

     ├── index.html
     ├── package.json
     ├── public
     │   └── favicon.ico
     ├── src
     │   ├── App.vue
     │   ├── assets
     │   │   └── logo.png
     │   ├── components
     │   │   └── HelloWorld.vue
     │   ├── main.js
     │   ├── router
     │   │   └── index.js
     │   └── views
     │       ├── Home.vue
     │       ├── about
     │       │   ├── index.vue
     │       │   └── router
     │       │       └── index.js
     │       └── indo
     │           ├── index.vue
     │           └── router
     │               └── index.js
     ├── tree.md
     ├── vite.config.js
     └── yarn.lock
    
     // about/router/index.js
     export default [
       {
         path: '/about',
         name: 'About',
         component: () => import('../index.vue'),
       },
     ];
    

    每一个模块都包含一个router文件夹,我们可以通过动态引入的方式引入模块中的路由,了解详情 不用一个一个去引入,在src/router中设置

    // src/router/index.js 
    import { createRouter, createWebHashHistory } from 'vue-router'
    import Home from '../views/Home.vue'
    
    const routesModules = import.meta.globEager('../views/**/*.js')
    const modules = []
    Object.keys(routesModules).forEach(key => {
      modules.push(...routesModules[key].default)
    })
    console.log('modules: ', modules);
    
    const routes = [
      {
        path: '/',
        name: 'Home',
        component: Home
      },
      ...modules
    ]
    
    const router = createRouter({
      history: createWebHashHistory(import.meta.env.BASE_URL),
      routes
    })
    
    export default router
    

    在链接中输入http://localhost:8000/#/info 内容显示Info,那么恭喜你已经配置成功了。

    2. 安装scss

    # NPM
    npm install scss -D
    
    # YARN 
    yarn add scss -D
    

    一般我们都是设置公用的scss文件,统一设置公用的样式,方便统一修改统一的样式

    1. 我们可以在src新建styles文件夹,新建common.scss文件
    $themeColor: #f4364c;
    
    2. 在vite.config.js中设置公用的引入common.scss就可以直接在vue文件中使用公用的样式了
    import { defineConfig } from 'vite'
    const {resolve} = require('path')
    import vue from '@vitejs/plugin-vue'
    
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [vue()],
      server: {
        port: 8000 // 配置启用的端口号
      },
      resolve:{
        // 设置别名
        alias:{
          '@/views': resolve(__dirname, 'src/views/'),
          '@/styles': resolve(__dirname, 'src/styles/')
        }
      },
      css: {
        preprocessorOptions: {
          // 引入公用的样式
          scss: {
            additionalData: `@import "@/styles/common.scss";`
          }
        }
      }
    })
    

    测试:

    # About.vue
    <template>
     <div class="about">About</div>
    </template>
    
    <script>
    export default {
    
    }
    </script>
    
    <style lang="scss" scoped>
    .about {
      color: themeColor;
     }
    </style>
    
    

    3. vuex

     # vuex正式版已经发布,我们使用4.0版本,
     # 如果你想下载最新版本 yarn add vuex@4. 会让你选择4.0所有版本,你选择想要的版本即可
    
     # NPM
     npm install vuex@4.0.0
    
     # YARN
     yarn add vuex@4.0.0
    
    1. src下添加store文件夹,新建index.js
     import {createStore} from 'vuex'
          
     const store = createStore({
       state: {
         count: 0
       },
       mutations: {
         increment (state) {
           state.count++
         }
       },
       getters: { },
       actions: { }
     })
    
     export default store
    
    2. 在main.js引入vuex
     import { createApp } from 'vue'
     import router from './router'
     import store from './store'
     import App from './App.vue'
    
     createApp(App).use(router).use(store).mount('#app')
    
    3. 持久化,需要下载vuex-persistedstate
     # NPM
     npm installvuex-persistedstate@4.0.0
    
     # YARN
     yarn add vuex-persistedstate@4.0.0
    
    4. store/index.js 中配置
      import { createStore } from 'vuex'
      import createPersistedState from 'vuex-persistedstate'
    
      const store = createStore({
        ...
    
        plugins: [
          createPersistedState({
            storage: window.sessionStorage // 修改存储的状态
          })
        ] // 状态持久化
      })
    
      export default store
    
    5. 如果想模块化,可以参考 详情

    4. Eslint

    让我们的代码有更好的代码规范和统一的代码格式,方面多人开发,和阅读代码。

    1. 首先安装eslint以及其他的依赖
     # NPM
     npm install eslint eslint-config-airbnb eslint-plugin-import eslint-plugin-vue -D
     
     # YARN 
     yarn add eslint eslint-config-airbnb eslint-plugin-import eslint-plugin-vue -D
    
    2. 根目录添加 .eslintrc.js
    module.exports = {
      extends: ['plugin:vue/vue3-essential', 'airbnb-base'],
      parserOptions: {
        ecmaVersion: 2020,
        sourceType: 'module',
      },
      plugins: ['vue'],
      rules: {
        // 自己写一些想配置的规则
        'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 生产环境禁用consele
        'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 生产环境禁用debugger
        'linebreak-style': 'off', // 忽略检测换行风格
        'vue/max-attributes-per-line': 'off', // 关闭强制 html 标签换行
        'no-param-reassign': ['error', { props: false }], // 允许修改参数中的属性值
        'prefer-destructuring': ['error', { object: true, array: false }], // 允许数组通过下标取值
        'max-len': 'off', // 对象选项
        'no-use-before-define': 'off', // 允许定义之前使用
        'func-names': 'off', // 允许使用匿名函数
        'no-shadow': ['error', { allow: ['state'] }], // 允许对其进行阴影处理
        'import/prefer-default-export': 'off', // 模块只输出一个变量时,是否需要添加default
        'no-plusplus': 'off', // 一元运算符
      },
      overrides: [
        {
          files: ['*.vue'],
          rules: {
            // 这里写覆盖vue文件的规则
          },
        },
      ],
    };
    
    
    3. 配置vscode

    根目录添加 .vscode文件夹,文件夹下添加settings.json

    // settings.json
    {
        "editor.formatOnSave": true,
        "editor.codeActionsOnSave": {
            "source.fixAll": true,
            "source.fixAll.eslint": true
        },
        "[json]": {
            "editor.defaultFormatter": "vscode.json-language-features"
        },
    }
    
    4. 测试eslint

    随便打开一个文件。我们用main.js为例,

    如果出现eslint报错的情况,恭喜eslint已经生效了。

    按下快捷键 Ctrl + Shift + P, 输入 ESLint: Manage Library Execution 选择并回车

    会出现下图显示:

    选中弹框的 Allow Everywhere 选项, 右下角的图标变为 √√ESLint

    点击保存就会自动格式化我们的代码以及规范我们的代码。

    了解更多 ESLint中文网 airbnb(爱彼迎)代码规范 airbnb代码规范 Vue代码规范

    5. 安装Element Plus

    # NPM
    npm install element-plus --save
    
    # YARN
    yarn add element-plus --save
    

    main.js中引入element-ui

    import { createApp } from 'vue';
    import ElementPlus from 'element-plus';
    import router from './router';
    import App from './App.vue';
    import 'element-plus/lib/theme-chalk/index.css';
    
    createApp(App).use(router).use(ElementPlus).mount('#app');
    

    6. axios

    1. 下载axios
    # NPM
    npm install axios --save
    
    # YARN
    yarn add axios --save
    
    2. 封装axios请求
    /**
     * @file axios请求封装
     */
    import axios from 'axios';
    import { ElMessage } from 'element-plus';
    // import { store } from '../store';
    
    // 请求失败错误信息提示
    function checkCode(message) {
      // 弹出错误信息
      ElMessage.closeAll();
      ElMessage({ message, type: 'error', customClass: 'deep-message' });
      // ElMessage.error(message)
    }
    
    // 响应时间
    axios.defaults.timeout = 10000;
    // `withCredentails`选项表明了是否是跨域请求
    axios.defaults.withCredentials = true;
    // 设置默认请求头
    axios.defaults.headers = {
      'X-Requested-With': 'XMLHttpRequest',
      'Content-Type': 'application/json; charset=UTF-8',
    };
    
    const pending = []; // 声明一个数组用于存储每个ajax请求的取消函数和ajax标识
    const cancelToken = axios.CancelToken;
    const removePending = (config) => {
      const resUrl = `${config.url}&${config.method}`;
      // eslint-disable-next-line no-restricted-syntax
      for (const p in pending) {
        if (pending[p].url === resUrl) { // 当当前请求在数组中存在时执行函数体
          pending[p].fn(); // 执行取消操作
          pending.splice(p, 1); // 把这条记录从数组中移除
        }
      }
    };
    
    // 添加请求拦截器
    axios.interceptors.request.use(
      (config) => {
        // 获取token
        // if (store.state.common.token) {
        //   // 判断是否存在token,如果存在的话,则每个http header都加上token
        //   config.headers.Authorization = store.state.common.token;
        // }
        removePending(config); // 在一个ajax发送前执行一下取消操作
        // eslint-disable-next-line new-cap
        config.cancelToken = new cancelToken((cf) => {
          // 这里的ajax标识我是用请求地址&请求方式拼接的字符串,当然你可以选择其他的一些方式
          pending.push({ url: `${config.url}&${config.method}`, fn: cf });
        });
        return config;
      },
      (error) =>
        // endLoading()
        // eslint-disable-next-line implicit-arrow-linebreak
        Promise.reject(error),
    
    );
    
    // 添加返回拦截器
    axios.interceptors.response.use(
      (response) => {
        // endLoading()
        removePending(response.config); // 在一个ajax响应后再执行一下取消操作,把已经完成的请求从pending中移除
        const { data, data: { code } } = response || {};
        const listCode = [0, 1001, 1000, 1100];
        if (typeof response !== 'undefined') {
          if (listCode.includes(code)) return data;
          if (response.data.msg) return response.data;
          checkCode(response.data.message);
        }
        return '';
      },
      (error) => {
        if (error && error.response) {
          switch (error.response.status) {
            case 400:
              error.message = '请求错误';
              break;
            case 401:
              error.message = '登录过期,请重新登录';
              // 跳到登录界面
              localStorage.clear();
              sessionStorage.clear();
              break;
            case 403:
              error.message = '拒绝访问';
              break;
            case 404:
              error.message = '请求失败';
              break;
            case 408:
              error.message = '请求超时';
              break;
            case 500:
              error.message = '服务器内部错误';
              break;
            case 501:
              error.message = '服务未实现';
              break;
            case 502:
              error.message = '无法连接服务器';
              break;
            case 503:
              error.message = '服务不可用';
              break;
            case 504:
              error.message = '连接服务器超时';
              break;
            case 505:
              error.message = 'HTTP版本不受支持';
              break;
            default:
          }
        } else {
          // error.message = '无法连接服务器'
        }
        // 对返回的错误处理
        return Promise.reject(error);
      },
    );
    
    export default {
      async get(url, params) {
        try {
          const res = await axios.get(url, { params });
          return typeof res.data !== 'undefined' && res.data;
        } catch (err) {
          return checkCode(err.message);
        }
      },
      async post(url, params) {
        try {
          const res = await axios({
            method: 'post',
            url,
            data: params,
          });
          return typeof res.data !== 'undefined' && res.data;
        } catch (err) {
          return checkCode(err.message);
        }
      },
      async put(url, params) {
        try {
          const res = await axios({
            method: 'put',
            url,
            data: params,
          });
          return typeof res.data !== 'undefined' && res.data;
        } catch (err) {
          return checkCode(err.message);
        }
      },
      async delete(url, params) {
        try {
          const res = await axios.delete(url, { params });
          return typeof res.data !== 'undefined' && res.data;
        } catch (err) {
          return checkCode(err.message);
        }
      },
      async all(url, params) {
        try {
          const res = await axios.all(url, { params });
          return typeof res.data !== 'undefined' && res.data;
        } catch (err) {
          return checkCode(err.message);
        }
      },
    };
    
    
    3. 本地调试设置跨域

    使用proxy代理设置跨域,查看详情

    // vite.config.js
    export default {
      resolve: {
        proxy: {
          '/api': {
            target: 'https://xxx.com/api',
            changeOrigin: true,
          },
        },
      },
    }
    
    4. 使用
    // about/api/index.js
    import $api from '@/utils/request';
    
    export default {
      getData(params) {
        return $api.get('/api/basis/Data',params);
      },
    };
    
    // about/index.vue
    <template>
      <div>about</div>
    </template>
    
    <script>
    import aboutApi from './api';
    
    export default {
      setup() {
        const test = async () => {
          const result = await aboutApi.getData();
          console.log('result: ', result);
        };
        test();
      },
    };
    </script>
    
    <style></style>
    
    

    其他功能正在开发,敬请期待!!!

  • 相关阅读:
    [BZOJ 1552] 排序机械臂
    [BZOJ 1124][POI 2008] 枪战 Maf
    [BZOJ 1647][USACO 2007 Open] Fliptile 翻格子游戏
    [BZOJ 1592] Making The Grade路面修整
    [BZOJ 3829][POI2014] FarmCraft
    [技术] 如何正确食用cnblogs的CSS定制
    [BZOJ 1458] 士兵占领
    今天写了一个Imageloader,,AndroidStudio报了Error:Execution failed for task ':app:mergeDebugResources'. > Error: Java.util.concurrent.ExecutionException: com.Android.ide.common.process.ProcessException: 这个错误
    Http响应码代表的含义
    获取WIFI列表,在旧手机上运行就没有问题,在新手机上就怎么也获取不到WIFI列表,长度一直为0,还不报异常,很疑惑。
  • 原文地址:https://www.cnblogs.com/wenxinsj/p/14626660.html
Copyright © 2020-2023  润新知