最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 总结 Vite2.x + Vue3.x 有哪些常用的基操| 8月更文挑战

    正文概述 掘金(ihoneys)   2021-08-02   844

    前言

    到现在 Vue3.0 正式发布快有一个年头了,同时后续也发布的更快的打包工具 Vite 也更新到了 2.x版本,相信有很多小伙伴也已经在公司的新项目中应用起来,体验这一快感,下面这篇文章总结下项目中基于 Vite2.x + Vue3.0 常用小基操。

    注册组件

    在开发项目多数情况少不了使用 UI 框架组件来快速开发搭建我们的页面,一般使用组件库时,为了减小包体积(tree-shshaking 技术),都采用按需加载的方式。

    以 Vant 组件使用为例,通常我们会:

    import { createApp } from "vue";
    import App from "./App.vue";
    
    const app = createApp(App);
    
    // 引入组件
    import {
      Progress,
      Picker,
      Popup,
      ....
    } from "vant";
    
    // app.use() 注册
    app.use(Progress)
       .use(Picker)
       .use(Picker)
       ...
       .mount("#app");
    
    

    简单的引用几个组件还好,看起来没有拉面条,想想就这样引入算了,如果有二十三十个就显得很长也会让 main.ts 越来越大,基于模块化开发思想,最好单独封装到一个配置文件中。

    创建一个 config 文件夹下 vant.config.ts 文件名中

    import {
      Progress,
      Picker,
      Popup,
      ....
    } from "vant";
    
    const components = {
      Progress,
      Picker,
      Popup,
      ....
    }
    
    // .use 内部会自动寻找 install 方法进行调用注册挂载
    const componentsInstallHandler = {
        install(app) {
            Object.keys(components).forEach(key => app.use(components[key]))
        }
    }
    
    export default componentsInstallHandler
    

    main.ts 中

    // ...省略 createApp 引入
    
    // 导入
    import vantComponentsInstall from "./config/vant.config";
    
    app
      .use(vantComponentsInstall)
      .mount("#app");
    

    这样操作完是不是舒服多了~

    组件全局注册

    自己编写了一个比如 <Header/> 组件想要全局使用,这时候可以调用 createApp() 返回的 component 函数进行全局注册

    // ...省略 createApp 引入
    
    import Header from '@/components/Header/Index.vue'
    
    app.component('Header', Header)
    

    过滤器

    在 3.x 中,过滤器已删除,不再支持。相反地,可以用方法调用或计算属性代替它。

    
    <template>
      <div>
          {{computedFunc('computed')}}
      </div>
    </template>
    <script lang="ts">
    import { computed, defineComponent} from "vue";
    export default defineComponent({
      setup() {
          // 使用 闭包 接受传递参数
          const computedFunc = () => {
              return val => val
          }
          return {
              computedFunc
          }
       }	
    })
    </script>
    
    

    全局过滤器

    比如多个组件中数据渲染值都需要解密后才能正确显示,不可能每一个组件里面都写 computed,这时候可以通过 全局属性 在所有组件中使用它:

    // main.ts
    const app = createApp(App)
    
    app.config.globalProperties.$filters = {
      decrypt(value) {
        return mdDecrypt(value)
    },
    

    然后,就可以通过 $filters 对象修改所有的模板:

    <template>
      <p>{{ $filters.decrypt(encryptVal) }}</p>
    </template>
    

    自定义 UI 框架主题色

    每个设计师采用的主题色不一样,UI 框架默认的主题色不是我们想要的,想必我们需要自定义配置一下。下面以 Vant 为例:

    import { defineConfig } from 'vite'
    
    export default defineConfig({
      css: {
        preprocessorOptions: {
          less: {
            javascriptEnabled: true,
            // 需要自定义样式变量名称
            modifyVars: {           
              'blue': '#00C6B8',
              'gray-7': '#333333',
              'gray-4': '#00C6B8',
               ...
            },
          },
        },
      },
    })
    
    

    服务代理 server

    在开发测试调用后端服务地址,少不了需要 server 代理,Vue2.x 配合 Vue-CLI 可以在 config/index.js 添加 proxyTable 修改添加, Vite 中又是怎么添加的呢,Vite 官网也有说明,下面看看如何配置:

    import { defineConfig } from 'vite'
    
    export default defineConfig({
      server: {
        port: 3006, // 设置端口,默认 3000
        open: true, // 设置启动时,自动打开浏览器
        cors: true, // 允许跨域
        host:'10.x.x.x', // 本地 IP 访问,如何移动端手机调试就需要填写本地 IP 了
        proxy: {
          '/api': {
            target: 'http://10.x.x.x.x',
            changeOrigin: true,
            secure: false,
            rewrite: path => path.replace('/api/', '/')
          }
          // 配置多个继续添加
          '/api2': {
            ...
          }
        },
      },
    })
    

    配置别名

    写法有很多种,可以是一个对象,或一个 { find, replacement } 具体可以看 options

    import vue from '@vitejs/plugin-vue'
    import { defineConfig } from 'vite'
    
    export default defineConfig({  
      resolve: {      
        alias: [
          {
            find: "@",
            replacement: resolve(__dirname, "src"),
          },
          {
            find: "@ASS",
            replacement: resolve(__dirname, "src/assets"),
          },
        ]
      },
        
      server: {
    	....
      },
    })
    

    移动端 rem 自适应

    结合使用 amfe-flexiblepostcss-pxtorem 实现移动端适配。

    amfe-flexible

    amfe-flexible 是配置克伸缩布局方案,主要将 1rem设为viewWidth/10。

    postcss-pxtorem

    postcss-pxtorem 是 postcss的插件,用于将像素单位生成 rem 单位。

    npm 安装

    npm i amfe-flexible -D
    npm i postcss-pxtorem -D
    

    安装完毕后,在 main.ts 中导入 amfe-flexible 插件

    // ...
    import 'amfe-flexible/index.js'
    

    postcss-pxtorem 配置

    配置 postcss-pxtorem 方式有三种,可以在 vite.config.ts、.postcssrc.ts、postcss.copnfig.ts 其中之一配置即可。

    vite.config.ts 中配置如下:

    import { defineConfig } from 'vite'
    
    export default defineConfig({
      css: {
        ... ,
        loaderOptions: {
          postcss: {
            plugins: [
              require('postcss-pxtorem')({
                rootValue: 37.5, // 根据设计稿宽度除以10进行设置,这边假设设计稿为375,即rootValue设为37.5,我这里设置 
                propList: ['*'] // // propList是设置需要转换的属性,这边*为所有都进行转换。
              })
            ]
          }
        }
      },
    })
    

    根目录创建 .postcssrc.ts 或者 postcss.copnfig.ts 配置如下:

    module.exports = {
      plugins: {
        autoprefixer: {
          overrideBrowserslist: [
            'Android 4.1',
            'iOS 7.1',
            'Chrome > 31',
            'ff > 31',
            'ie >= 8',
            'last 10 versions', // 所有主流浏览器最近10版本用
          ],
        },
        postcss-pxtorem: {
          rootValue: 37.5,
          propList: ['*'], 
        },
      },
    }
    
    

    配置完毕重启看看效果:

    总结 Vite2.x + Vue3.x 有哪些常用的基操| 8月更文挑战

    还可以 引入 rem.js 方式,不过需要编写样式的时候自己 px 转 rem ,好在 vscode 扩展商店中有px to rem 插件一件转换,这里展开了,可以自行 google 一下就有了。

    环境变量

    有时候项目开发中需要部署有三种运行环境中比如 测试环境(test)、开发环境(dev)、生成环境(prod),请求的接口地址也需要更换,如何动态的更换呢? Vite 在一个特殊的 import.meta.env 对象上暴露环境变量,可以通过暴露的环境变量来判断是运行在哪一个环境中。

    npm run dev 运行 import.meta.env 暴露的变量值为 development

    npm run build import.meta.env 暴露的变量值为 production

    还有一种 测试环境(test)如何拿到呢?

    可以通过 package.json 配置 scripts run 命令

      "scripts": {
        "dev": "vite",
        "build": "vite build",
        "test:build": "vite build --mode test", 
      },
    

    运行 npm run test:build import.meta.env 暴露变量值为 test 了 --mode xxx 名称可以自定义

    请求 URL 统一管理 config.ts:

    export const DEV_BASE_URL = "https://xxx"
    export const TEST_BASE_URL = "https://xxx"
    export const PRO_BASE_URL = "https://xxx"
    

    以封装 axios 设置 baseURL 为例:

    import { DEV_BASE_URL, PRO_BASE_URL, TEST_BASE_URL, TIMEOUT } from "./config";
    
    const envMap = {
      development: DEV_BASE_URL,
      production: PRO_BASE_URL,
      test: TEST_BASE_URL,
    };
    
    const base_URL = envMap[import.meta.env.MODE];
    
    // axios
    const instance = axios.create({
      baseURL: base_URL,
      timeout: 30000,
    });
    

    hooks 使用

    升级 Vue3 后,让人最脑壳痛应该不是 Compostion API 语法,而是提供了给我们全新的组织代码的思维方式。

    刚开始 Vue3.0 正式发布学习完之后,代码也是遵循 Compostion API 正确用法,可是当组件庞大,逻辑复杂,代码量也是很多,发现比 Options API 写法维护性更差,也是慢慢写成了 拉面条...

    下面结合真实业务需求讲解一下

    比如有一个获取验证码方法,点击获取完毕60s倒计时后才能重新获取,正常霹雳巴拉我们会这么写:

    example.vue

    <template>
      <button @click="onGetCode">{{ codeText }}</button>
    </template>
    <script lang="ts">
    import { defineComponent, reactive, toRefs } from "vue";
    export default defineComponent({
      setup(props, ctx) {
        const state = reactive({
          isGetCode: false,
          codeText: '获取验证码',
          countDown: 60,
          phone: ''
        })
        // 点击后倒计时
        const countTime = () => {
          state.isGetCode = true
          let timer
          timer = setInterval(
            (function setIntervalFunc() {
              if (countDown !== 0) {
                state.codeText = `重新发送${countDown.value--}`
              } else {
                state.isGetCode = false
                state.codeText = '获取验证码'
                state.countDown = 60
                clearInterval(timer)
              }
              return setIntervalFunc
            })(),
            1000
          )
        }
        // 获取验证码请求
        const onGetCode = async () => {
          const { success, message } = await getPhoneCode(encrypt(state.phone))
          if (success) {
            countTime()
            Toast.success(message)
          }
        }
        return {
          ...toRefs(state),
          onGetCode
        }
      }
    })
    </script>
    

    从新上面代码看没有问题啊,Compostion API 不就是这么用啊,梭哈完毕,可是再想想,如何这个页面只是其中一个逻辑,还有十个逻辑,都内聚在一起,依次继续写在后面,写到后面不就是我们所说的拉面条了吗?

    所以可以单独将逻辑拆分到一个文件中

    // useVerificationCode.js
    import { reactive, toRefs } from "vue";
    
    export default const useVerificationCode = () => {
        const state = reactive({
            isGetCode: false,
            codeText: '获取验证码',
            countDown: 60,
            phone: ''
        })
        // 点击后倒计时
        const countTime = () => {
            state.isGetCode = true
            let timer
            timer = setInterval(
                (function setIntervalFunc() {
                    if (countDown !== 0) {
                        state.codeText = `重新发送${countDown.value--}`
                    } else {
                        state.isGetCode = false
                        state.codeText = '获取验证码'
                        state.countDown = 60
                        clearInterval(timer)
                    }
                    return setIntervalFunc
                })(),
                1000
            )
        }
        // 获取验证码请求
        const onGetCode = async () => {
            const { success, message } = await getPhoneCode(encrypt(state.phone))
            if (success) {
                countTime()
                Toast.success(message)
            }
        }
        return {
            ...toRefs(state)
            onGetCode,
        }
    }
    

    再看看改造后:

    // example.vue
    <template>
      <button @click="onGetCode">{{ codeText }}</button>
    </template>
    <script lang="ts">
    import { defineComponent } from "vue";
    // 引入 useVerificationCode.js
    import useVerificationCode from "./useVerificationCode.js";
    export default defineComponent({
      setup(props, ctx) {
          // 获取验证码
         const { onGetCode, isGetCode, codeText, countDown, phone } = useVerificationCode()
         
         // ...
         // ...
        return {
          onGetCode, 
          isGetCode, 
          codeText, 
          countDown, 
          phone
        }
      }
    })
    </script>
    

    这样是不是清爽许多了,以前错误的观点,就是只有复用的逻辑才应该封装到 hook 中,在 官方的给例子 中,并不是强调逻辑复用,而是逻辑关注点分离,到这里相信大家都明白该怎么写了。但是在简单逻辑的组件中,过度抽离就没必要了。

    总结

    目前自己应用 Vue3.0 开发中的小项目中还没有遇到过大坑,面向百度、文档都能轻松解决,赶紧用起来吧,两个字 好使,Vite 编译是真的快~,尤大给力( ̄▽ ̄)。


    起源地下载网 » 总结 Vite2.x + Vue3.x 有哪些常用的基操| 8月更文挑战

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元