为 VUE 脚手架添加开发常用的插件/配置

为脚手架(按需)添加开发常用的插件/配置

一、css相关配置

1. 添加全局样式变量

定义一些全局的主题样式变量,统一各页面样式时十分有用

ts 复制代码
// vite.config.ts
export default defineConfig({
  // ...其他配置
  css: {
   preprocessorOptions: {
     scss: {
       // ...其他配置
       // 添加额外的代码变量,可以全局引用。如果在这里添加了样式,那么样式在最终编译会重复生成
       additionalData: "$color: red;",
       // 变量名可以直接替换为文件导入,比如:
       // additionalData: @import '@/styles/theme.scss';
     }
   }    
  },
  // ..其他配置
})

2. 自动填加浏览器前缀

可以避免手动处理浏览器兼容问题,专注在样式开发工作上

  1. 安装autoprefixer :autoprefixer是添加前缀(vite已经内置postcss,无需再单独下载)

    ts 复制代码
     pnpm add autoprefixer -D
  2. vite.config.ts中配置

    ts 复制代码
    // vite.config.ts
    import autoprefixer from 'autoprefixer';
    export default defineConfig({
     // ...其他配置
     css: {
    // ..其他配置
     postcss: {
       plugins: [
         autoprefixer({
           overrideBrowserslist: [
             'Android 4.1',
             'iOS 7.1',
             'Chrome > 31',
             'ff > 31',
             'ie >= 8'
           ],
          grid: true
        })
      ]
     }
     },
     // ..其他配置
    })

3. 将类名处理成哈希(可选)

避免类名重复导致全局样式冲突

vue的scoped也能一定程度上解决这个问题。简单项目建议直接使用scoped,复杂样式管理可以使用 CSS modules 文件或者通过postcss-modules自定义将类名处理成哈希值。
CSS modules也是基于postcss-modules实现的,配置 CSS modules 的行为,选项将被传递给postcss-modules 。任何以 .module.scss 为后缀名的文件都被认为是一个导入CSS Module这样的文件会返回一个相应的模块对象

  • 下面简单写一下CSS Module的使用,postcss-modules可以自行了解,也差不多。
vue 复制代码
<script setup lang="ts">
  import { useCssModule } from 'vue';
  const style = useCssModule();
</script>

<style module lang="scss">
/** 也可以把样式写在以 `.module.scss` 为后缀名的文件中再导入使用 **/
// @import '**/**.module.scss';
.example {
  text-decoration: dashed;
  display: flex;
  flex-flow: row nowrap;
  justify-content: center;
}
</style>
  • 可以在vite.config.ts中配置生成规则:
ts 复制代码
// vite.config.ts
export default defineConfig({
  // ...其他配置
  css: {
   // ..其他配置
    modules: {
       generateScopedName: '[name]__[local]___[hash:base64:5]'
    }
  },
  // ..其他配置
})

4. 将px转rem(可选)

自适应不同屏幕

在自适应不同屏幕时会发挥作用,尤其是在还原ui设计图时。如果你在项目中使用了UI框架,请确认框架组件是否支持pxtorem

  1. 下载postcss-pxtorem插件
shell 复制代码
pnpm add postcss-pxtorem -D
  1. vite.config.ts中配置
ts 复制代码
// vite.config.ts
// @ts-expect-error postcss-pxtorem还没有官方的ts包
import pxtorem from 'postcss-pxtorem';
   
export default defineConfig({
  // ...其他配置
  css: {
  // ..其他配置
    postcss: {
      plugins: [
        pxtorem({
          // 1rem = 14px
          rootValue: 14,
          // 需要转换的属性,除 border 外所有px 转 rem
          propList: ['*', '!border'],
          // 排除node_modules
          exclude: '/node_modules/*',
          // 是否要在媒体查询中转换px
          mediaQuery: false,
          // 设置要转换的最小像素值
          minPixelValue: 2
        })
      ]
    }
  },
  // ..其他配置
})
  1. 添加 remUnit 适配代码
ts 复制代码
// remUnit.ts
function setRem(): void {
  const designWidth: number = 1920 // 设计稿宽度
  const html: HTMLElement = document.documentElement
  const width: number = html.clientWidth

  html.style.fontSize = `${(width / designWidth * 14)}px`
}

// 初始化和窗口变化时调用
setRem()
window.addEventListener('resize', setRem)

export default setRem
// 这里用gpt将上面的代码改写成了一段更严谨的代码,随便用哪个都可以
// remUnit.ts
class RemAdapter {
  private designWidth: number
  private rootValue: number
  
  constructor(designWidth: number = 1920, rootValue: number = 14) {
      this.designWidth = designWidth
      this.rootValue = rootValue
      this.init()
  }
  
  private calculateRem(): void {
      const html: HTMLElement = document.documentElement
      const width: number = html.clientWidth
      
      html.style.fontSize = `${(width / this.designWidth * this.rootValue)}px`
  }
  
  private init(): void {
      this.calculateRem()
      window.addEventListener('resize', this.calculateRem.bind(this))
    }
}
  
// 创建实例
new RemAdapter()
  
export default RemAdapter
  1. main.ts 中引入:
ts 复制代码
import './remUnit'

5. tailwindcss v3.x(可选)

可以当做postcss的插件使用。

  1. 下载和初始化
shell 复制代码
 pnpm add -D tailwindcss@3
 // 下载完成后初始化
 npx tailwindcss init
  1. 修改配置文件
ts 复制代码
// `tailwind.config.ts`
/** @type {import('tailwindcss').Config} */
export default {
  content: [
  "./index.html",
  "./src/**/*.{vue,js,ts,jsx,tsx}"
  ],
  theme: {
  extend: {},
  },
  plugins: [],
}

// vite.config.ts
import tailwindcss from 'tailwindcss';
export default defineConfig({
    // ...其他配置
    css: {
    // ..其他配置
        postcss: {
            plugins: [
            // ...其他配置
                tailwindcss()
            ]
        }
    },
       // ..其他配置
})
  1. 添加 Tailwind 的基础指令,并在main.ts中引入
ts 复制代码
/* src/tailwind.css */*
@tailwind base;
@tailwind components;
@tailwind utilities;
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import './tailwind.css'; // 包含 Tailwind 指令的 CSS 文件 
import './style.scss'

createApp(App).mount('#app')

6. tailwindcss v4.0(可选)

可以当做 vite 的插件使用。版本4集成了autoprefixer,所以如果使用这个版本,需要删除autoprefixer插件的使用

  1. 下载和初始化
shell 复制代码
 pnpm add tailwindcss @tailwindcss/vite
  1. 修改配置文件
js 复制代码
// vite.config.ts
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
  plugins: [
    tailwindcss(),
  ],
})
  1. 添加 Tailwind 的基础指令,并在main.ts中引入
css 复制代码
/* src/tailwind.css */
@import "tailwindcss";

/*  main.ts */
import { createApp } from 'vue'
import App from './App.vue'
import './tailwind.css'; // 包含 Tailwind 指令的 CSS 文件 
import './style.scss'

createApp(App).mount('#app')

二、静态资源处理

静态资源?

静态资源本身并不是标准意义上的模块,因此对它们的处理和普通的代码是需要区别对待的。一方面我们需要解决资源加载 的问题,对 Vite 来说就是如何将静态资源解析并加载为一个 ES 模块的问题;另一方面在生产环境下我们还需要考虑静态资源的部署问题、体积问题、网络性能问题,并采取相应的方案来进行优化。

1. 图片无损压缩

图片资源的体积往往是项目产物体积的大头,如果能尽可能精简图片的体积,那么对项目整体打包产物体积的优化将会是非常明显的

  • 安装
shell 复制代码
pnpm add vite-plugin-imagemin -D
  • vite.config.ts中配置
ts 复制代码
import viteImagemin from 'vite-plugin-imagemin';

export defaul defineConfig({
  plugins:[
    // 其他配置
    viteImagemin({
      // 是否在控制台输出压缩结果
      verbose: false, 
      // 无损压缩配置,无损压缩下图片质量不会变差
      optipng: {
        // 优化级别:
        optimizationLevel: 7
      },
      gifsicle: {
        optimizationLevel: 7,
        interlaced: false
      },
      mozjpeg: {
        // 压缩质量,范围为`0` (最差)到`100` (完美)。
            quality: 20,
          },
      pngquant: {
        quality: [0.8, 0.9],
        speed: 4,
      },
      // svg 优化
      svgo: {
        plugins: [
          {
            // 删除与文档宽度和高度匹配的[`viewBox`]
            name: 'removeViewBox'
          },
          {
            // 从文档中的元素中删除空属性
            name: 'removeEmptyAttrs',
            active: false
          }
        ]
      }
    })
  ]
})

2. 以组件的形式加载Svg

svg可以作为静态图片加载,但是如果作为一个组件引用的话,可以很方便的修改svg的各种属性,且比img标签等引入方式更加优雅(如果你想在项目中使用雪碧图优化svg,可以先跳过这一小节)

  • 安装
shell 复制代码
pnpm add vite-svg-loader -D
  • vite.config.ts中配置
ts 复制代码
import svgLoader from 'vite-svg-loader'

export default defineConfig({
  plugins: [
    // 其他配置
    svgLoader()
  ]
})
  • 使用

    这个插件提供几种显示导入:url、raw、component import svg from './my-icon.svg?url' import svg from './my-icon.svg?raw' import svg from './my-icon.svg?component'

url: 可以使用?url后缀将 SVG 作为 URL 导入

raw: 可以使用?raw后缀将 SVG 作为 字符串 导入

component: 可以使用?component后缀将 SVG 作为 vue组件 导入

**当未提供显示参数时,SVG 将默认作为 Vue 组件导入。**可以使用defaultImport配置设置来更改此设置,具体设置可参考官方说明

3. 动态引入静态资源

使用动态路径访问assets资源

在前面,我们已经为./src/assets路径下的静态资源设置了别名,在加载图片时就不用手动寻址。比如:<img src="@assets/images/code-icon.png" />。 但是在使用动态路径访问assets资源时会导致打包后路径错误,找不到图片文件。所以我这里在src/utils/tools.ts中添加了一个getAssetsFile方法,用于使用动态路径获取assets下的静态资源,代码如下:

ts 复制代码
/**
* @description 获取assets静态资源路径,在使用动态路径时很有用
* */

export const getAssetsFile = (url: string) => {
  return new URL(`../assets/${url}`, import.meta.url).href;
};

4. 雪碧图优化(可选)

svg 文件一般体积不大,但 Vite 中对于 svg 文件会始终打包成单文件,当项目中使用了较多的svg图标时,会导致网络请求增加,大量的 HTTP 请求会导致网络解析耗时变长,页面加载性能直接受到影响。

(不过这个问题只在http1.1中受影响,因为http2的多路复用设计可以解决大量http请求导致的网络加载性能问题。如果项目依旧使用的是http1.1并且存在较多svg,建议使用雪碧图技术进行优化)

  • 安装
shell 复制代码
pnpm add -D @spiriit/vite-plugin-svg-spritemap
  • vite.config.ts中配置
ts 复制代码
// vite.config.js / vite.config.ts
import VitePluginSvgSpritemap from '@spiriit/vite-plugin-svg-spritemap'

export default {
  plugins: [VitePluginSvgSpritemap('./src/icons/*.svg', {
  prefix: 'sprites_icon-', // 前缀
  output: {
    view: true,
    use: true
  }
  })]
}
  • 使用

这个插件也支持把svg导入为vue组件使用,如果项目中需要雪碧图优化,那么上面第2点提到的以组件的形式加载Svg的插件就不用下了,用这一个插件就可以了。

vue 复制代码
// 该插件支持两种显示引入后缀用于转化组件,也可以不适用后缀,但样式会不太一样:
<script setup lang="ts">
import ViteView from '@assets/icons/vite.svg?view'; // 转化为vue组件,适配大小
import ViteUse from '@assets/icons/vite.svg?use'; // 直接使用,原始大小
</script>

<template>
  <ViteView />
  <ViteUse />
</template>
  • 解决import无法找到模块的报错
ts 复制代码
官方给的解决方案是在 vite-env.d.ts中添加下面这句代码,如果你添加了之后import语句还在报错,请重启编辑器

/// <reference types="@spiriit/vite-plugin-svg-spritemap/client" />

5. 单文件 or 内联?

参考网址

在 Vite 中,所有的静态资源都有两种构建方式,一种是打包成一个单文件,另一种是通过 base64 编码的格式内嵌到代码中。

这两种方案到底应该如何来选择呢?

对于比较小的资源,适合内联到代码中,一方面对代码体积的影响很小,另一方面可以减少不必要的网络请求,优化网络性能。而对于比较大的资源,就推荐单独打包成一个文件,而不是内联了,否则可能导致上 MB 的 base64 字符串内嵌到代码中,导致代码体积瞬间庞大,页面加载性能直线下降。

Vite 中内置的优化方案是下面这样的:

  • 如果静态资源体积 >= 4KB,则提取成单独的文件
  • 如果静态资源体积 < 4KB,则作为 base64 格式的字符串内联

上述的4 KB即为提取成单文件的临界值,当然,这个临界值你可以通过build.assetsInlineLimit自行配置,如下代码所示:

typescript 复制代码
// vite.config.ts
{
  build: {
    // 8 KB
    assetsInlineLimit: 8 * 1024
  }
}

svg 格式的文件不受这个临时值的影响,始终会打包成单独的文件,因为它和普通格式的图片不一样,需要动态设置一些属性,所以采用了上面的一些优化措施

三、安装pinia

应该在什么时候使用 Store?

一个 Store 应该包含可以在整个应用中访问的数据。这包括在许多地方使用的数据,例如显示在导航栏中的用户信息,以及需要通过页面保存的数据,例如一个非常复杂的多步骤表单。

另一方面,你应该避免在 Store 中引入那些原本可以在组件中保存的本地数据,例如,一个元素在页面中的可见性。

并非所有的应用都需要访问全局状态,但如果你的应用确实需要一个全局状态,那 Pinia 将使你的开发过程更轻松。 (不要) 滥用 store

1. 安装

shell 复制代码
// 安装pinia和pinia持久化插件

pnpm add pinia pinia-plugin-persistedstate

2. 配置

/src下新建文件夹stores,创建index.ts文件如下:

ts 复制代码
import { createPersistedState } from 'pinia-plugin-persistedstate';

const pinia = createPinia();
pinia.use(
	createPersistedState({
	    // 全局 key 配置接受传入 Store key 的函数,并返回一个新的 storage 密钥。
		key: (id: string) => `__persist__${id}`,
		// 该配置将会使所有 Store 持久化存储,且必须配置 persist: false 显式禁用持久化。
		auto: true
	})
);
export default pinia;

3. vs code配置

  • 为编辑器添加快速生成Pinia store模板代码,下面定义了两种Pinia store的模板:
json 复制代码
1. 打开vs code
2. 按下 Ctrl+Shift+P (Windows) 或 Cmd+Shift+P (Mac) 打开命令面板
3. 输入 "Configure User Snippets"
4. 选择 "New Global Snippets file..." 或者选择特定的语言(如 "typescript.json")
5. 如果选择新建全局片段,输入文件名(如 "pinia")

在自动创建好的文件中粘贴一下代码:
{
  "Pinia Options Store Boilerplate": {
    "scope": "javascript,typescript",
    "prefix": "pinia-options",
    "body": [
      "import { defineStore, acceptHMRUpdate } from 'pinia'",
      "",
      "export const use${TM_FILENAME_BASE/^(.*)$/${1:/pascalcase}/}Store = defineStore('$TM_FILENAME_BASE', {",
      " state: () => ({",
      "   $0",
      " }),",
      " getters: {},",
      " actions: {},",
      "})",
      "",
      "if (import.meta.hot) {",
      " import.meta.hot.accept(acceptHMRUpdate(use${TM_FILENAME_BASE/^(.*)$/${1:/pascalcase}/}Store, import.meta.hot))",
      "}",
      ""
    ],
    "description": "Bootstrap the code needed for a Vue.js Pinia Options Store file"
  },
  "Pinia Setup Store Boilerplate": {
    "scope": "javascript,typescript",
    "prefix": "pinia-setup",
    "body": [
      "import { defineStore, acceptHMRUpdate } from 'pinia'",
      "",
      "export const use${TM_FILENAME_BASE/^(.*)$/${1:/pascalcase}/}Store = defineStore('$TM_FILENAME_BASE', () => {",
      " $0",
      " return {}",
      "})",
      "",
      "if (import.meta.hot) {",
      " import.meta.hot.accept(acceptHMRUpdate(use${TM_FILENAME_BASE/^(.*)$/${1:/pascalcase}/}Store, import.meta.hot))",
      "}",
      ""
    ],
    "description": "Bootstrap the code needed for a Vue.js Pinia Setup Store file"
  }
}

配置完成后使用方法:

1. 创建一个新的 .ts 文件
2. 在文件中输入 `pinia-options` 或 `pinia-setup`
3. 按下 Tab 键,代码片段将自动展开

下面的代码是我使用`pinia-setup`生成的:
import { defineStore, acceptHMRUpdate } from 'pinia'
export const useTestStore = defineStore('test', () => {
	return {}
})
if (import.meta.hot) {
	import.meta.hot.accept(acceptHMRUpdate(useTestStore, import.meta.hot))
}
  • 这里附带贴一下vue的快速生成代码模板:
json 复制代码
1. 打开vs code
2. 按下 Ctrl+Shift+P (Windows) 或 Cmd+Shift+P (Mac) 打开命令面板
3. 输入 "Configure User Snippets"
4. 选择'vue'

{
	"Vue3 Template": {
		"prefix": "v3",
		"body": [
			"<template>",
			"\t<div>",
			"\t\t$1",
			"\t</div>",
			"</template>",
			"",
			"<script setup>",
			"import { ref } from 'vue'",
			"",
			"$2",
			"</script>",
			"",
			"<style scoped>",
			"$3",
			"</style>"
		],
		"description": "Vue 3 基础模板",
	},
	"Vue3-ts-scss Template": {
		"prefix": "v3ts",
		"body": [
			"<template>",
			"\t<div>",
			"\t\t$1",
			"\t</div>",
			"</template>",
			"",
			"<script lang='ts' setup>",
			"",
			"$2",
			"</script>",
			"",
			"<style lang='scss' scoped>",
			"$3",
			"</style>"
		],
		"description": "Vue 3 ts scss模板"
	},
	"Vue3 Watch": {
		"prefix": "v3watch",
		"body": [
			"watch(${1:source}, (newValue, oldValue) => {",
			"\t${2:// 处理逻辑}",
			"})"
			],
			"description": "Vue 3 侦听器"
			},
			"Vue3 Props": {
			"prefix": "v3props",
			"body": [
			"const props = defineProps({",
			"\t${1:propName}: {",
			"\t\ttype: ${2:String},",
			"\t\trequired: ${3:true},",
			"\t\tdefault: ${4:null}",
			"\t}",
			"})"
		],
		"description": "Vue 3 组件 props 定义"
	},
	"Vue3 Emits": {
		"prefix": "v3emits",
		"body": [
			"const emit = defineEmits(['${1:eventName}'])"
		],
		"description": "Vue 3 组件 emits 定义"
	}
}
	

四、安装router

1. 安装

shell 复制代码
pnpm add vue-router@4

2. 添加路由

​ 这一步可以按自己的习惯创建文件,下面是代码示例:

ts 复制代码
// src/router/modules/home/index.ts
import { RouteRecordRaw } from 'vue-router';

const homeRoutes: RouteRecordRaw[] = [
  {
    path: '/',
    name: 'HelloWorld',
    component: () => import('@/components/HelloWorld.vue'),
    meta: {
      title: 'Hello World',
      keepAlive: true
    }
  }
];

export default homeRoutes;

// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import homeRoutes from './modules/home';

const router = createRouter({
  history: createWebHistory(),
  routes: [...homeRoutes]
});

export default router;

// src/main.ts
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';

createApp(App).use(router).mount('#app');
vue 复制代码
// src/App.vue
<template>
  <router-view></router-view>
</template>

五、自动生成路由和类型(可选)

unplugin-vue-router

默认情况下,该插件检查src/pages文件夹中是否有任何.vue文件,并根据文件名生成相应的路由结构。这样,您在向应用程序添加路由时不再需要维护routes数组,**只需将新的.vue组件添加到路由文件夹中,然后让这个插件完成剩下的工作!**对于不同复杂度的项目,自动生成路由有不同的优缺点,按需使用。

1. 安装

shell 复制代码
pnpm add -D unplugin-vue-router

2. 配置

ts 复制代码
// vite.config.ts
import VueRouter from 'unplugin-vue-router/vite'
export default defineConfig({
	plugins: [
		VueRouter({ 
			routesFolder: 'src/views',
			dts: 'types/typed-router.d.ts'
		}),
		// ⚠️ Vue must be placed after VueRouter()
		Vue(),
	],
})
json 复制代码
// tsconfig.json
{
	"include":[
		// other files...
		"types/typed-router.d.ts"
	 ],
	 "compilerOptions":{ 
		 // ...
		 "moduleResolution": "Bundler", 
		 // ...
	 }
 }
  • 如果用了自动导入,那么import中的'vue-router'需要替换为VueRouterAutoImports:
ts 复制代码
// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite';
import { VueRouterAutoImports } from 'unplugin-vue-router';

export default defineConfig(({ mode }) => {
	return {
		pulgins: [
			AutoImport({
				// imports: ['vue', 'vue-router', 'pinia']修改为:
				imports: ['vue', VueRouterAutoImports, 'pinia']
				// ...其他配置
			});
		]
	}
});

3. 创建

使用这个插件后页面组件需要按照指定规则创建

  • src/views文件夹中添加一个index.vue组件。这将在/呈现为首页。

  • 如果页面由动态路由链接,那么文件名应该写为[xx].vue,更多规则可以参看文档,举例:

    • /: -> index.vue
    • /about: -> about.vue
    • /users: -> users/index.vue
    • /users/:id: -> users/[id].vue, id 就是路由参数
    • /users/[[id]].vue: -> /users/:id? ,id是可选参数
    • /users/[slugs]+.vue : -> /users/:slugs+ ,slugs是可重复参数
    • /pages/[...path].vue: -> /:path(.*),可捕获所有路由,可用于添加404
    • /pages/[email protected]: -> 将定义为命名视图
    • 注意:index.vue文件名必须全部小写
  • /src/main.ts或者router.ts中导入插件

ts 复制代码
import { routes } from 'vue-router/auto-routes'

const router = createRouter({ history: createWebHistory(), routes, }) 

4. 初始化

  • 添加插件后,启动开发服务器,会在typed-router.d.ts生成类型的第一个版本
  • vite-env.d.ts中添加类型,避免ts报错
ts 复制代码
/// <reference types="unplugin-vue-router/client" />

unplugin-vue-router 将添加一个虚拟vue-router/auto模块,该模块从vue-router导出所有内容,并从unplugin-vue-router/runtime导出一些额外功能。

建议避免在新项目中使用vue-router/auto 。保留它是为了与使用它的现有项目兼容,并且将来可能会被删除。

您可以通过将此设置添加到.vscode/settings.json来从 VSCode 导入建议中排除vue-router/auto

json 复制代码
{
  "typescript.tsdk": "node_modules/typescript/lib",
  "typescript.preferences.autoImportFileExcludePatterns": ["vue-router/auto$"]
}

六、添加页面跳转进度条

1. 安装

shell 复制代码
pnpm add nprogress
pnpm add @types/nprogress -D

2. 封装

ts 复制代码
// 新建文件:/src/utils/nporgress.ts
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

//全局进度条的配置
NProgress.configure({
	easing: 'ease', // 动画方式
	speed: 1000, // 递增进度条的速度
	showSpinner: false, // 是否显示加载ico
	trickleSpeed: 200, // 自动递增间隔
	minimum: 0.3, // 更改启动时使用的最小百分比
	parent: 'body', //指定进度条的父容器
})

// 打开进度条
export const start = () => {
	NProgress.start()
}

// 关闭进度条
export const close = () => {
	NProgress.done()
}
相关推荐
程序员小刚3 分钟前
基于SpringBoot + Vue 的考勤管理系统
vue.js·spring boot·后端
code bean1 小时前
【C#】`Task.Factory.StartNew` 和 `Task.Run` 区别
前端·vue.js·c#
倔强青铜三1 小时前
WXT浏览器插件开发中文教程(9)----WXT配置详解之Vite配置
前端·javascript·vue.js
倔强青铜三1 小时前
WXT浏览器插件开发中文教程(10)----WXT配置详解之构建模式
前端·javascript·vue.js
倔强青铜三2 小时前
WXT浏览器插件开发中文教程(8)----WXT配置详解之运行时配置
前端·javascript·vue.js
倔强青铜三2 小时前
WXT浏览器插件开发中文教程(6)----WXT配置详解之环境变量
前端·javascript·vue.js
倔强青铜三2 小时前
WXT浏览器插件开发中文教程(6)----WXT配置详解之自动导入
前端·javascript·vue.js
倔强青铜三2 小时前
WXT浏览器插件开发中文教程(5)----WXT配置详解之浏览器启动设置
前端·javascript·vue.js
倔强青铜三2 小时前
WXT浏览器插件开发中文教程(4)----WXT配置详解之manifest清单
前端·javascript·vue.js
梦想家加一4 小时前
elementUI el-image图片加载失败解决
javascript·vue.js·elementui