Vue3实战——项目搭建(二)

一、全家桶

vue3+vite
vue-router
pinia 状态管理、pinia-plugin-persist 数据存储
axios 接口请求
postcss-px-to-viewport 移动端适配
vant4 移动端UI库

二、开始

1、创建项目 vue3_h5

yarn create vite vue3_h5 --template vue

2、风格规范

组件名:单文件组件的文件名—单词大写开头 (PascalCase)、横线连接 (kebab-case)。
紧密耦合的组件名:子组件应该以父组件名作为前缀命名。
Prop名:命名使用 camelCase,在模板中使用 kebab-case。
指令缩写,用 : 表示 v-bind: ,用 @ 表示 v-on:
Props顺序:依次指令、属性和事件。
组件选项顺序:

export default {
  name: '',
  components: {},
  props: {},
  data() {},
  computed: {},
  watch: {},
  created() {},
  mounted() {},
  unmounted() {},
  methods: {},
};

三、项目配置

1. postcss-px-to-viewport 移动端适配

功能:将px单位转换为视口单位的 (vw, vh, vmin, vmax) 的 PostCSS 插件。
postcss-px-to-viewport:插件文档。
vite postcss:Vite自身已经集成PostCSS。
配置参考:在Vite中配置方法。

// vite.config.js文件
import postcsspxtoviewport from 'postcss-px-to-viewport'
css: {
    postcss: {
      plugins: [
        postcsspxtoviewport({
          unitToConvert: 'px', // 要转化的单位
          viewportWidth: 375, // UI设计稿的宽度
          unitPrecision: 6, // 转换后的精度,即小数点位数
          propList: ['*'], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
          viewportUnit: 'vw', // 指定需要转换成的视窗单位,默认vw
          fontViewportUnit: 'vw', // 指定字体需要转换成的视窗单位,默认vw
          selectorBlackList: ['ignore-'], // 指定不转换为视窗单位的类名,
          minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
          mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
          replace: true, // 是否转换后直接更换属性值
          // exclude: [/node_modules/], // 设置忽略文件,用正则做目录名匹配
          exclude: [],
          landscape: false // 是否处理横屏情况
        })
      ]
    }
  },

2. 配置别名、开发服务器配置

// vite.config.js文件
import { resolve } from 'path';
import postcsspxtoviewport from 'postcss-px-to-viewport'
  resolve:{
    alias:{
      '@':resolve('./src')
    }
  },
  server:{
      proxy: {
        [VITE_API_BASE_URL]: {
          target: VITE_BASE_URL,
          changeOrigin: true,
          rewrite: (path) => {
            return path.replace('/api/', '/');
          }
        }
      },
      port:8000, // 服务器端口
      open: true, // 服务器启动时自动在浏览器中打开
      cors: true // 允许跨域
    },

3. 安装UI库-vant3

(1)安装UI库vant3 yarn add vant
(2)按需自动导入UI库组件:见步骤【4】。
(3)直接在模板中使用使用 Vant 组件
<van-button type="primary" /> Vant 中unplugin-vue-components 会解析模板并自动注册对应的组件。

说明:Vant中个别组件以函数的形式提供(Toast,Dialog,Notify 和 ImagePreview),使用 unplugin-vue-components 插件来自动引入组件样式,则无法正确识别。

(4)函数形式组件,使用时需要在具体页面引入使用。

  • 引入组件:import { Toast,Dialog } from 'vant';

  • 还需要引入组件的样式。【手动引入、插件】

    • A. 需要在公共模块中,手动引入组件的样式。
      import 'vant/es/toast/style';// Toast
      import 'vant/es/dialog/style';// Dialog
      
    • B. 插件vite-plugin-style-import配置自动引入样式:步骤【5】——【不推荐!】

4. unplugin-vue-components 按需自动导入组件

插件文档:https://github.com/antfu/unplugin-vue-components
功能:导入自定义组件、自动导入UI库。
原理:插件会生成一个ui库组件以及指令路径components.d.ts文件。
自动导入参考:https://juejin.cn/post/7012446423367024676#heading-8

安装:yarn add unplugin-vue-components -D
配置:

// vite.config.js文件
import Components from 'unplugin-vue-components/vite'
import {VantResolver} from 'unplugin-vue-components/resolvers'
  plugins: [
    Components({
      // 指定组件位置,默认是src/components
      dirs: ['src/components'],
      // ui库解析器,也可以自定义
      resolvers: [
        VantResolver(),
      ],
      // 配置文件生成位置
      dts: 'src/components.d.ts'
    })
  ],

5. vite-plugin-style-import 按需自动导入样式

vite-plugin-style-import:https://github.com/vbenjs/vite-plugin-style-import/blob/main/README.zh_CN.md
功能:按需导入组件库样式。
警告:【不推荐!】vant组件样式前后存在覆盖问题。

安装:yarn add vite-plugin-style-import -D
安装consola:用于 Node.js 和浏览器的优雅控制台记录器。

import {createStyleImportPlugin, VantResolve} from 'vite-plugin-style-import'
// vite.config.js文件
createStyleImportPlugin({
      resolves: [
        VantResolve(),
      ],
      // 自定义规则
      libs: [
        {
          libraryName: 'vant',
          esModule: true,
          resolveStyle: (name) => {
            return `../es/${name}/style/index`
          }
        }
      ]
    })

6. unplugin-auto-import 自动导入vue3的hooks

功能:支持vue, vue-router, vue-i18n, @vueuse/head, @vueuse/core等自动引入。
表现:不需要引入import { ref, computed } from 'vue'
原理:安装的时候会自动生成auto-imports.d文件(默认是在根目录)。

// vite.config.js文件
import AutoImport from 'unplugin-auto-import/vite';
AutoImport({
      dts: 'src/auto-imports.d.ts',
      imports: [
        'vue',
        'pinia',
        'vue-router',
      ],
    })

7. pinia状态管理

  1. 安装pinia yarn add pinia
    pinia-plugin-persist:持久化存储插件。参考

  2. 配置

// store/index.js
import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persist'

const store = createPinia()
store.use(piniaPersist)
export default store

// main.js
import store from './store'
app.use(store)

8. vue-router路由

  1. 安装vue-router yarn add vue-router

  2. 配置

// router/index.js
import { createRouter, createWebHashHistory } from 'vue-router';

const routes = [
  {
    path: '/',
    redirect: '/home',
    component: () => import('@/views/home/index.vue'),
  },
  {
    name: 'home',
    path: '/home',
    component: () => import('@/views/home/index.vue'),
  },
  {
      name: 'detail',
      path: '/detail',
      component: () => import('@/views/detail/index.vue'),
    },
];

const router = createRouter({
  history: createWebHashHistory('/'),
  routes: routes,
});

export default router;

// main.js
import router from './router/index'
app.use(router)

注意:使用createWebHashHistory模式,在浏览器访问链接才能找到正确路径。

9. axios网络请求

  1. 安装axios npm install axios

  2. 配置

import axios from 'axios';
import { showToast,showLoadingToast,closeToast  } from 'vant';

// 运行时获取环境变量,使用import.meta.env
const { VITE_API_BASE_URL, VITE_BASE_URL, VITE_NODE_ENV } = import.meta.env
// 创建实例时配置默认值
const instance = axios.create({
  baseURL: VITE_NODE_ENV === 'production' ? VITE_BASE_URL : VITE_API_BASE_URL,
  withCredentials: true,
  timeout: 5000,
  headers:{
    'Content-Type': 'application/x-www-form-urlencoded'
  }
});

// 添加请求拦截器
instance.interceptors.request.use(
  (config) => {
    if(config.url.indexOf('&__act=export_string')>=0){
      config.headers['Content-Type'] = 'application/json';
    }
    // 不传递默认开启loading
    if (!config.hideLoading) {
      showLoadingToast({
        forbidClick: true,
      });
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  },
);

// 添加响应拦截器
instance.interceptors.response.use(
  (response) => {
    closeToast();
    if(response.data.data == undefined){
      showToast('接口请求失败,请稍后再试!');
    }
    const res = response.data.data[0];
    if (res.code !== 200) {
      showToast(res.errmsg);
      return Promise.reject(res.errmsg || 'Error');
    } else {
      return Promise.resolve(response);
    }
  },
  (error) => {
    if (error.message?.includes('timeout')) {
      showToast('请求超时!');
    }
    return Promise.reject(error.message);
  },
);

const request = (config)=> {
  return new Promise((resolve, reject) => {
    instance
      .request(config)
      .then((res) => resolve(res.data))
      .catch((err) => reject(err));
  });
};

export default request;

10. unplugin-vue-define-options [网络下载问题,未用到]

功能:组件内显示定义 name 属性,覆盖推导出的文件名称。
参考:https://juejin.cn/post/7142797517355221023

  1. 安装 yarn add unplugin-vue-define-options -D

  2. 配置 vite

// vite.config.ts
import DefineOptions from 'unplugin-vue-define-options/vite'
import Vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [Vue(), DefineOptions()],
})

3.编写定义

// 默认写法
<script>
  export default {
    name: "MyComponent"
  }
</script>

<script setup lang="ts">
</script>

// 添加插件后
<script setup lang="ts">
defineOptions({
  name: "MyComponent"  
})
</script>

11. sass作为css预处理

  1. 安装 yarn add sass -D
    Vite提供了对 .scss 文件的内置支持,没有必要安装特定的 Vite 插件,但必须安装预处理器依赖。

  2. 对 variables、common.scss作全局引入。

// vite.config.ts
css: {
    preprocessorOptions: {
      // 引入公用的样式
      scss: {
        additionalData: `@import "@/styles/common.scss";@import "@/styles/variable.scss";`,
      }
    }
  }
  1. 通过 <style lang="sass">自动开启。

12. autoprefixer 浏览器前缀处理插件

  1. 安装
    yarn add autoprefixer

  2. 配置

// vite.config.ts
import autoprefixer from 'autoprefixer'
css: {
    postcss: {
      plugins: [
        autoprefixer({
          overrideBrowserslist:[
            "Android > 4.1",
            "iOS >= 7.1",
            'Chrome > 31',
            "ff >= 31",
            'ie>= 8',
          ],
          grid:true
        })
      ],
    }
  },

13. 打包文件夹分离

vite默认打包后,js 和 css 是全部混在一起的,将 js 和 css 文件夹分离。

// vite.config.ts
build: {
      brotliSize: false,
      // 消除打包大小超过500kb警告
      chunkSizeWarningLimit: 2000,
      // 在生产环境移除console.log
      terserOptions: {
        compress: {
          drop_console: true,
          drop_debugger: true
        }
      },
      assetsDir: 'static/assets',
      // 静态资源打包到dist下的不同目录
      rollupOptions: {
        output: {
          chunkFileNames: 'static/js/[name]-[hash].js',
          entryFileNames: 'static/js/[name]-[hash].js',
          assetFileNames: 'static/[ext]/[name]-[hash].[ext]'
        }
      }
    }

注意:组件xx.vue需要使用不同name命名,不可都用xx/index.vue,否则打包固定文件名,会缺少样式。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容