vue3+ts+vant4+pinia+axios+scss proceso básico de creación de un proyecto

vue3+ts+vant4+pinia+axios+scss proceso básico de creación de un proyecto

自我记录

Directorio de artículos

1. Introducción, instalación y uso de pnpm (se puede omitir)

1. Introducción

En esencia, es una herramienta de gestión de paquetes, no diferente de npm/yarn, la principal ventaja es

  • La instalación del paquete es extremadamente rápida.
  • Utilización eficiente del espacio en disco
  • pnpm es una herramienta eficiente de administración de paquetes, básicamente igual que npm y Yarn.

2.Instalación

npm i pnpm -g

3.Uso

comando npm equivalente pnpm
instalación npm instalación pnpm
npm i axios pnpm agregar axios
npm i paquete web -D pnpm agregar paquete web -D
npm ejecutar desarrollador pnpm agregar paquete web -D

2. Creación de proyectos

1. create-vueCrea un proyecto usando andamios.

dirección de referencia de create-vue: https://github.com/vuejs/create-vue

2. Pasos

2.1 Usar comando:

pnpm create vue
# or
npm init vue@latest
# or
yarn create vue

La siguiente imagen es para pnmpdemostración (igual que el artículo)
Insertar descripción de la imagen aquí

2.2 Seleccionar dependencias del proyecto:

✔ Project name: … czbk-h5-test
✔ Add TypeScript? … No / `Yes`
✔ Add JSX Support? … `No` / Yes
✔ Add Vue Router for Single Page Application development? … No / `Yes`
✔ Add Pinia for state management? … No / `Yes`
✔ Add Vitest for Unit Testing? … `No` / Yes
✔ Add an End-to-End Testing Solution? › `No`
✔ Add ESLint for code quality? … No / `Yes`
✔ Add Prettier for code formatting? … No / `Yes`

Scaffolding project in /Users/sougewang/test/test/czbk-h5-test...

Done. Now run:

  cd czbk-h5-test
  pnpm install
  pnpm format
  pnpm dev

1. Nombre del proyecto
2. Si se debe admitir TS
3. Si se debe admitir JSX
4. Si se debe usar un paquete de enrutamiento de un solo archivo
5. Si se debe usar Pinia para la administración del estado
6. Si se requieren pruebas unitarias
7. Si se debe usar Pinia para la administración del estado Se requieren pruebas finales
8. Si se requiere verificación de verificación ESLint
9. Si se necesita la herramienta de formato Prettier

2.3 Instalar dependencias y ejecutar

如下图

Insertar descripción de la imagen aquí
Directorio de proyecto predeterminado

El total normal se 5173debe a que ya abrí una ventana, por lo que 5174esto se puede ignorar o configurar más tarde.
Nota: El siguiente es czbk-h5un ejemplo . 5174Son czbk-h5-testtodas iguales. Acabo de pasar por el proceso de creación de capturas de pantalla.

3. Instalación del complemento Vscode y configuración prefabricada de eslint

1. Instalación: extensions.jsondebe instalarse en el interior.

Ps: Si vscode no se ha instalado, aparecerá un mensaje para instalarlo en la esquina inferior derecha cuando se abra el proyecto.

  • Funciones del lenguaje Vue (Volar) Compatibilidad con la sintaxis de vue3
  • Complemento TypeScript Vue (Volar) Mejores consejos ts en vue3
  • Verificación del estilo del código Eslint

注意: Después de la instalación Prettier, deshabilítelo para evitar eslintconflictos con el proyecto.

了解: Para proyectos grandes y medianos, se recomienda activar el modo de alojamiento TS para obtener indicaciones de escritura mejores y más rápidas.

Insertar descripción de la imagen aquí

2.configuración prefabricada de eslint

Utilice: configuración prefabricada de eslint y comprenda la función de configuración (cada empresa es diferente y depende del individuo)
reglas comunes https://prettier.io/docs/en/options.html

Añadiendo .eslintrc.cjs_

/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')

module.exports = {
    
    
  root: true,
  extends: [
    'plugin:vue/vue3-essential',
    'eslint:recommended',
    '@vue/eslint-config-typescript',
    '@vue/eslint-config-prettier/skip-formatting'
  ],
  parserOptions: {
    
    
    ecmaVersion: 'latest'
  },
  rules: {
    
    
    'prettier/prettier': [
      // 格式:单引号,没有分号,行宽度100字符,没有对象数组最后一个逗号,换行字符串自动(系统不一样换行符号不一样)
      'warn',
      {
    
    
        singleQuote: true,
        semi: false,
        printWidth: 80,
        trailingComma: 'none',
        endOfLine: 'auto'
      }
    ],
    'vue/multi-word-component-names': [
      //vue 组件需要大驼峰命名,除去 index 之外,App 是默认支持的
      'warn',
      {
    
    
        ignores: ['index']
      }
    ],
    'vue/no-setup-props-destructure': ['off'] //允许对 props 进行解构,我们会开启解构保持响应式的语法糖
  }
}

Habrá muchos errores en el archivo del proyecto, así que no te preocupes por ahora.

3. Problema de formato de reparación de archivos

También puede ejecutar el comando para reparar el formato de todos los archivos o guardar cada archivo usted mismo.

pnpm format
or
pnpm lint

4. Ajuste de la estructura del directorio e interpretación de enrutamiento

1. Ajuste del catálogo

./src
├── assets        `静态资源,图片...`
├── components    `通用组件`
├── composable    `组合功能通用函数`
├── icons         `svg图标`
├── router        `路由`
│   └── index.ts
├── services      `接口服务API`
├── stores        `状态仓库`
├── styles        `样式`
│   └── main.scss
├── types         `TS类型`
├── utils         `工具函数`
├── views         `页面`
├── main.ts       `入口文件`
└── App.vue       `根组件`

Insertar descripción de la imagen aquí
Cree las carpetas correspondientes y elimine archivos redundantes.

2. Interpretación de rutas

import {
    
     createRouter, createWebHistory } from 'vue-router'

// vue2的路由
// 1.import VueRouter from 'vue-router'
// 2.const router = new VueRouter({ routes: [ // 路由规则 ] })
// 3.选择路由模式 hash /#/user   history /user

// 现在vue3的路由
// 1.创建路由实例 createRouter({ //配置对象 })
// 2.配置选项中 routes: [ // 路由规则 ]
// 3.createWebHistory 使用路由history 模式
// 4.createWebHashHistory(), //使用路由hash模式
// 5.import.meta.env.BASE_URL 路由的基准路由 create-vue 脚手架提供的环境变量 ps:在vite.config.ts 文件可以配置base: '/',
const router = createRouter({
    
    
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: []
})

export default router

3. Uso de enrutamiento y protección

NProgressLea otro artículo, el objetivo principal es implementar la función de la barra de progreso al cargar la página,
poner la ruta primero al frente y la última en primer lugar, y modificar el título.

import {
    
     useUserStore } from '@/stores'
import {
    
     createRouter, createWebHistory } from 'vue-router'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

const router = createRouter({
    
    
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
    
    
      path: '/login',
      component: () => import('@/views/Login/index.vue'),
      meta: {
    
     title: '登录' }
    },
    {
    
    
      path: '/',
      redirect: '/home',
      component: () => import('@/views/Layout/index.vue'),
      children: [
        {
    
    
          path: '/home',
          component: () => import('@/views/Home/index.vue'),
          meta: {
    
     title: '首页' }
        },
        {
    
    
          path: '/user',
          component: () => import('@/views/User/index.vue'),
          meta: {
    
     title: '我的' }
        }
      ]
    }
  ]
})
// 修改进度条插件的配置
NProgress.configure({
    
    
  showSpinner: false
})
// 前置首位 访问权限控制
router.beforeEach((to) => {
    
    
  // 开启页面进度条
  NProgress.start()
  // 用户仓库
  const store = useUserStore()
  // 用户白名单
  const wihteList = ['/login']
  // 没有token 并且 不再白名单 则跳转登录页
  if (!store.user?.token && !wihteList.includes(to.path)) return '/login'
  // 放行 return true  可以不用写
})
// 后置守卫
router.afterEach((to) => {
    
    
  // 设置页面标题
  document.title = to.meta.title || '奔跑的代码!'
  NProgress.done()
})
export default router

5. Instale Pinia& y use almacenamiento local

Para obtener más información, consulte otro artículo: Comience rápidamente con la persistencia de datos de Vue3+Pinia+ en 20 minutos.

Seis Instalar scss

El proyecto utiliza el preprocesador sass. Instale sass para admitir la sintaxis scss:

pnpm add sass -D

Uso de archivos:

<style scoped lang="scss"></style>

7. Instalar y usar Vant

1.Instalar Vant

# Vue 3 项目,安装最新版 Vant
npm i vant
# 通过 yarn 安装
yarn add vant
# 通过 pnpm 安装
pnpm add vant

2. Importar y utilizar globalmente

src/main.tsTenga en cuenta que el archivo de estilo global debe estar en la parte inferior para facilitar la sobrescritura del estilo del componente vant más adelante.

import {
    
     createApp } from 'vue'

import App from './App.vue'
import router from './router'
// 引入 pinia
import pinia from './stores'
// 样式全局使用
import 'vant/lib/index.css'
import './styles/main.scss'

const app = createApp(App)

// vue使用pinia插件,use(pinia的插件)
app.use(pinia)
app.use(router)
app.mount('#app')

Los componentes se introducen manualmente según demanda para probar si están disponibles.

<script setup lang="ts">
// 组件按需手动引入测试是否可用
import {
    
     Button as VanButton } from 'vant'
</script>

<template>
  <van-button>按钮</van-button>
</template>

<style scoped lang="scss"></style>

3.Vant se adapta al terminal móvil para utilizar vw

3.1 Instalar complementospostcss-px-to-viewport

npm install postcss-px-to-viewport -D
# or
yarn add -D postcss-px-to-viewport
# or
pnpm add -D postcss-px-to-viewport

3.2 Configurar y usar complementos

czbk-h5/postcss.config.js
Insertar descripción de la imagen aquí

3.3 Resolver problemas de informes de errores

3.3.1 Error del editor [plugin:vite:css] (si no se informa ningún error, puede omitirlo)

Error: [vite] Internal server error: Failed to load PostCSS config
Solución: cambie postcss.config.jsel nombre del archivo a, postcss.config.cjses decir, cambie .jsel sufijo del archivo a.cjs

3.3.2 Informe de errores de la consola (no afecta el uso)

Insertar descripción de la imagen aquí
Solución: se puede ignorar o utilizar postcss-px-to-viewport-8-pluginen lugar del complemento actual

4. Cargue componentes automáticamente a pedido

Es problemático utilizar componentes manualmente según demanda y es necesario importarlos primero. La función de configuración se importa automáticamente según demanda y se utiliza directamente. Documentación oficial

4.1 Instalación

# 通过 npm 安装
npm i unplugin-vue-components -D
# 通过 yarn 安装
yarn add unplugin-vue-components -D
# 通过 pnpm 安装
pnpm add unplugin-vue-components -D

4.2 Configuración

vite.config.ts

import {
    
     fileURLToPath, URL } from 'node:url'

import {
    
     defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 引入按需导入插件
import Components from 'unplugin-vue-components/vite'
// 各种组件库的解析器 //里面还有 ElementUiResolver,ElementPlusResolverOptions,AntDesignVueResolver等常见的组件库
import {
    
     VantResolver } from 'unplugin-vue-components/resolvers'

// https://vitejs.dev/config/
export default defineConfig({
    
    
  // 默认'/' 是基准地址
  base: '/',
  plugins: [
    // 解析单文件组件的插件
    vue(),
    //使用按需导入插件 默认自动加载 components 下的组件,通用级别组件.
    Components({
    
    
      // 默认是true 开启自动生成组件的类型声明文件,vant的组件已经有类型声明文件,只要导入了就会使用类型声明.
      dts: false,
      // 在main.ts 已经引入了所有的组件样式,不需要自动导入样式,只需要自动导入组件即可
      resolvers: [VantResolver({
    
     importStyle: false })]
    })
  ],
  resolve: {
    
    
    alias: {
    
    
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

No es necesario introducirlo al usarlo.

<script setup lang="ts"></script>
<template>
  <van-button>按钮</van-button>
</template>

<style scoped lang="scss"></style>

Insertar descripción de la imagen aquí

5. Personaliza el tema con variables css.

src/App.vueEstilo predeterminado
Insertar descripción de la imagen aquí
Utilice variables css para personalizar el tema del proyecto y modificar el documento oficial del tema vant
src/styles/main.scss

// 项目共用的样式文件
:root {
    
    
    --cz-primary: #16C2A3;
    --cz-text1: red;
    --cz-text2: pink;
    // 覆盖vant主体色
    --van-primary-color: var(--cz-primary);
}

src/App.vueusar

<script setup lang="ts">
import {
    
     Button as VanButton } from 'vant'
</script>

<template>
  <!-- 验证vant颜色被覆盖 -->
  <van-button type="primary">按钮</van-button>
  <a href="#">测试</a>
</template>

<style scoped lang="scss">
// 使用css全局变量
a {
    
    
  color: var(--cz-text1);
}
</style>

效果
Insertar descripción de la imagen aquí

6. Encapsulación secundaria de componentes NavBar para implementar títulos públicos

6.1 Diseño, función y uso

src/components/CpNavBar.vue

<script setup lang="ts">
import {
    
     useRouter } from 'vue-router'
// 拿路由实例
const router = useRouter()
const props = defineProps<{
    
    
  title?: string
  rightText?: string
  back?: () => void
}>()
const emit = defineEmits<{
      
       (e: 'click-right'): void }>()
const onClickLeft = () => {
    
    
  // 扩展 back 属性,如果有就执行 back 对应的函数。
  // 给全屏弹出层使用
  if (props.back) {
    
    
    return props.back()
  }
  // TODO 点击左侧返回按钮
  // 实现返回 如果有当前网站的上一次历史记录 就执行back返回
  // 没有历史记录则跳转到 首页
  if (history.state?.back) {
    
    
    router.back()
  } else {
    
    
    router.push('/home')// 为了测试功能时否正常 后续需要换成 '/'
  }
}
const onClickRight = () => {
    
    
  // TODO 点击右侧文字按钮
  emit('click-right')
}
</script>

<template>
  <van-nav-bar
    left-arrow
    fixed
    :title="title"
    :right-text="rightText"
    @click-left="onClickLeft"
    @click-right="onClickRight"
  />
</template>

<style lang="scss" scoped>
:deep() {
    
    
  .van-nav-bar {
    
    
    &__arrow {
    
    
      font-size: 18px;
      color: var(--cz-text1);
    }

    &__text {
    
    
      font-size: 15px;
    }
  }
}
</style

La razón por la que se puede utilizar src/views/Login/index.vue
sin introducir <Cp-nav-bar />componentes es porque 4. 自动按需加载组件los elementos de configuración internos se pueden consultar para obtener comentarios.

<script setup lang="ts">
const fn = () => {
    
    
  console.log('点击了右侧')
}
</script>
<template>
  <div class="login-page">
    <cp-nav-bar title="登录" right-text="注册" @click-right="fn" />
  </div>
</template>
<style lang="scss" scoped>
.login {
    
    
  &-page {
    
    
    padding-top: 46px;
  }
}
</style>

效果
Insertar descripción de la imagen aquí

6.2 Agregar clases de componentes a componentes encapsulados secundarios

Agregue un tipo al componente para que haya indicaciones al escribir propiedades y eventos (TS puede identificarlo), este también es un método de escritura de código fuente que imita el componente Vant.

src/types/components.d.ts

// 给components 下的全局组件设置类型
// 1. 导入组件实例
import CpNavBar from '@/components/CpNavBar.vue'
// 2. 声明 vue 类型模块
declare module 'vue' {
    
    
  // 3. 给 vue  添加全局组件类型,interface 和之前的合并
  interface GlobalComponents {
    
    
    // 指定组件类型,typeof(从一个JS对象中得到他对应的TS类型) 从组件对象得到类型,设置给全局组件 CpNavBar
    CpNavBar: typeof CpNavBar
  }
}

Insertar descripción de la imagen aquí

8. Ejes de embalaje secundario

1. Instale axios y configure

1. Documentación china
2. Documentación de github

npm install axios
or
yarn add axios
or
pnpm add axios

src/utils/rquest.ts

// 二次封装axios
import router from '@/router'
import {
    
     useUserStore } from '@/stores'
import axios, {
    
     type Method } from 'axios'
import {
    
     showToast } from 'vant'
// 1. axios的配置
// 1.1 创建一个新的axios实例,配置基准地址,配置响应超时时间
// 1.2 添加请求拦截器,在请求头携带token
// 1.3 添加响应拦截器,判断业务是否成功,剥离无效的数据,401错误拦截去登录页面(删除当前用户信息),
const baseURL = 'xxxxxxxxx'
const instance = axios.create({
    
    
  baseURL,
  timeout: 10000
})
// 请求拦截器
instance.interceptors.request.use(
  (config) => {
    
    
    // 修改config,比如:修改请求头
    // 获取token===>就是获取user
    const store = useUserStore()
    if (store.user?.token && config.headers) {
    
    
      config.headers.Authorization = `Bearer ${
      
      store.user.token}`
    }
    return config
  },
  (err) => Promise.reject(err)
)
// 响应拦截器
// 将来  axios.get()
// .then(res=>{ // res 就是后台的数据,之前的res.data })
// .catch(e=>{ // 200+10001这种情况,e就是res.data , 如果是状态吗的错误 401 403 404 e 就错误对象  })
instance.interceptors.response.use(
  (res) => {
    
    
    // status 是200是响应成功的,res.data.code 是10000业务成功
    // 如果不是 10000 呢,使用 vant 的轻提示,报错阻断程序
    if (res.data.code !== 10000) {
    
    
      showToast(res.data.message || '网络异常')
      return Promise.reject(res.data)
    }
    // 剥离无效数据
    return res.data
  },
  // 401处理
  (err) => {
    
    
    // 请求报错,响应出错
    // 遇见401跳转登录
    // 1. 现在在 /user/patient 页面下,发起一个获取用户信息的请求,但是此时token失效
    // 2. 跳转登录页面,登录成功之后,需要跳转回 /user/patient 页面 (默认跳转 /user 首页)
    // vue2  $router 路由实例,提供路由相关函数操作  $route  路由相关信息,query params path 。。。
    if (err.response.status === 401) {
    
    
      // 需要删除用户信息
      const store = useUserStore()
      store.delUser()
      // /user/patient?id=1000
      // path  /user/patient  不带查询参数
      // fullPath  /user/patient?id=1000  完整路径
      // currentRoute 是一个 ref 创建的数据,需要.value
      router.push(`/login?returnUrl=${
      
      router.currentRoute.value.fullPath}`)
    }
    return Promise.reject(err)
  }
)
// obj = { name: 'jack', age: 100 }  obj['name'] ===> const name = 'name'  obj[name]

// 2. 请求工具函数
// 2.1 参数:url  method  submitData
// 2.2 返回:instance 调用接口的promise对象
// const request = (url: string, method: string, submitData?: object) => {
    
    
//   return instance.request({
    
    
//     url,
//     method,
//     // 区分get和其他请求post
//     // get 提交数据,选项:params
//     // 其他请求post 提交数据,选项:data
//     [method.toLowerCase() === 'get' ? 'params' : 'data']: submitData
//   })
// }
// res响应数据类型
type Data<T> = {
    
    
  code: string
  message: string
  data: T
}
const request = <T>(
  url: string,
  method: Method = 'get', // 默认是get
  submitData?: object // 可以不传
) => {
    
    
  // 泛型的第二个参数,可以自定义响应数据类型
  return instance.request<T, Data<T>>({
    
    
    url,
    method,
    // 区分get和其他请求post
    // get 提交数据,选项:params
    // 其他请求post 提交数据,选项:data // toLowerCase 将字符串转换为小写字母
    [method.toLowerCase() === 'get' ? 'params' : 'data']: submitData
  })
}
// baseURL 基准地址
// instance 是配置好的axios
// request 用来调用接口
export {
    
     baseURL, instance, request }

prueba de uso simplesrc/App.vue

<script setup lang="ts">
import {
    
     useUserStore } from './stores'
import type {
    
     User } from './types/user'

import {
    
     request } from './utils/rquest'
const store = useUserStore()
const login = () => {
    
    
  // 接口地址(去除基准路径之后的地址), 请求方式 , 请求参数
  request<User>('login/password', 'POST', {
    
    
    mobile: '12345678900',
    password: '111111'
  })
    .then((res) => {
    
    
      // 存储到本地
      store.setUser(res.data)
    })
    .catch((e) => {
    
    
      // 异常捕获
      console.log(e)
    })
}
</script>
<template>
  <van-button type="primary" @click="login">登录</van-button>
</template>

9. Mapa svg empaquetado con componentes de iconos

Implementación: empaquete la imagen svg en el proyecto de acuerdo con el archivo de íconos y use el ícono a través del componente

1.Instalación y configuración

Documento de referencia: https://github.com/vbenjs/vite-plugin-svg-icons
¿Es el producto un paquete de archivos de iconos? Se generará una estructura svg (creada por js) que contiene todos los iconos, entendido como精灵图
安装

yarn add vite-plugin-svg-icons -D
# or
npm i vite-plugin-svg-icons -D
# or
pnpm install vite-plugin-svg-icons -D

Configurar el icono de svg empaquetadovite.congfig.ts

import {
    
     fileURLToPath, URL } from 'node:url'

import {
    
     defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 引入按需导入插件
import Components from 'unplugin-vue-components/vite'
// 各种组件库的解析器 //里面还有 ElementUiResolver,ElementPlusResolverOptions,AntDesignVueResolver 等常见的组件库
import {
    
     VantResolver } from 'unplugin-vue-components/resolvers'
// 配置svg精灵图插件
+import {
    
     createSvgIconsPlugin } from 'vite-plugin-svg-icons'
+import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
    
    
  // 默认'/' 是基准地址
  base: '/',
  plugins: [
    // 解析单文件组件的插件
    vue(),
    //使用按需导入插件 默认自动加载 components 下的组件,通用级别组件.
    Components({
    
    
      // 默认是true 开启自动生成组件的类型声明文件,vant的组件已经有类型声明文件,只要导入了就会使用类型声明.
      dts: false,
      // 在main.ts 已经引入了所有的组件样式,不需要自动导入样式,只需要自动导入组件即可
      resolvers: [VantResolver({
    
     importStyle: false })]
    }),
+    // 打包svg图标目录
+    createSvgIconsPlugin({
    
    
+      // 指定需要缓存的图标文件夹 (打包指定svg图标的目录) //路径转换为绝对路径
+      iconDirs: [path.resolve(process.cwd(), 'src/icons')]
+    })
  ],
  resolve: {
    
    
    alias: {
    
    
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

entre src/main.tscomillas

import {
    
     createApp } from 'vue'

import App from './App.vue'
import router from './router'
// 引入 pinia
import pinia from './stores'
// 使用svg精灵图
+import 'virtual:svg-icons-register'
// 样式全局使用
import 'vant/lib/index.css'
import './styles/main.scss'

const app = createApp(App)

// vue使用pinia插件,use(pinia的插件)
app.use(pinia)
app.use(router)
app.mount('#app')

2.Fácil de usar

existirsrc/views/Login/index.vue

Por ejemplo: src/icons/user/add.svg
'icon-[dir]-[name]' #es fijo, tiene icon-un comienzo fijo, direl directorio donde se encuentra el ícono namey el nombre del ícono.

<script setup lang="ts">
const fn = () => {
    
    
  console.log('点击了右侧')
}
</script>
<template>
  <div class="login-page">
    <cp-nav-bar title="登录" right-text="注册" @click-right="fn" />
    <!-- 测试svg -->
    <svg aria-hidden="true">
      <!-- src/icons/user/add.svg -->
      <!-- 'icon-[dir]-[name]' # 是固定的 icon- 固定开头 dir 图标所在目录 name 图标的名称 -->
      <use href="#icon-user-add" />
    </svg>
  </div>
</template>
<style lang="scss" scoped>
.login {
    
    
  &-page {
    
    
    padding-top: 46px;
  }
}
</style>

效果
Insertar descripción de la imagen aquí

3. Encapsular componentes svg y usarlos

crearsrc/components/CpIcon.vue

<script setup lang="ts">
// 提供一个props 属性 确定使用哪个图标 使用的规则: 文件夹名称+图片名称 user-add
defineProps<{
      
       name: string }>()
</script>

<template>
  <svg aria-hidden="true" class="cp-icon">
    <!-- src/icons/user/add.svg    -->
    <!-- 'icon-[dir]-[name]' # 是固定的 icon- 固定开头 dir 图标所在目录 name 图标的名称  #icon-user-add -->
    <use :href="`#icon-${name}`" />
  </svg>
</template>

<style lang="scss" scoped>
.cp-icon {
    
    
  // 通过font-size 控制图片的大小(和字体一样大)
  width: 1em;
  height: 1em;
}
</style>

definir tiposrc/types/components.d.ts

// 给components 下的全局组件设置类型
// 1. 导入组件实例
import CpNavBar from '@/components/CpNavBar.vue'
+import CpIcon from '@/components/CpIcon.vue'
// 2. 声明 vue 类型模块
declare module 'vue' {
    
    
  // 3. 给 vue  添加全局组件类型,interface 和之前的合并
  interface GlobalComponents {
    
    
    // 指定组件类型,typeof(从一个JS对象中得到他对应的TS类型) 从组件对象得到类型,设置给全局组件 CpNavBar
    CpNavBar: typeof CpNavBar
+    CpIcon: typeof CpIcon
  }
}

usarsrc/views/Login/index.vue

<script setup lang="ts">
const fn = () => {
  console.log('点击了右侧')
}
</script>
<template>
  <div class="login-page">
    <cp-nav-bar title="登录" right-text="注册" @click-right="fn" />
    <cp-icon name="user-add" />
    <div style="font-size: 40px; color: red">
      <cp-icon name="user-add" />
    </div>
  </div>
</template>
<style lang="scss" scoped>
.login {
  &-page {
    padding-top: 46px;
  }
}
</style>

效果

Algunos íconos pueden establecer el color de acuerdo con el valor del color en el estilo. Si el ícono tiene esta función depende de si la interfaz de usuario está activada al tomar imágenes.

Insertar descripción de la imagen aquí

¡Seguirá actualizándose en el futuro!

Supongo que te gusta

Origin blog.csdn.net/zhgweb/article/details/129730493
Recomendado
Clasificación