D32 Vue2 + Vue3 K124-K143

D32.Vue

 F21.创建vue3项目(K124-K129)

     该笔记是从vue2过渡到vue3的,所以不会特别详细的介绍某些vue2学过的,主要介绍vue3新增的
  1.Vue3快速上手
  A. Vue3简介
   1)2020年9月18日,Vue.js发布3.0版本,代号:One Piece(海贼王)
   2)耗时2年多、2600+次提交、30+个RFC、600+次PR、99位贡献者
  B. Vue3带来了什么
   1)性能的提升
    a. 打包大小减少41%
    b. 初次渲染快55%, 更新渲染快133%
    c.内存减少54%
    d. …
   2)源码的升级
    a. 使用Proxy代替defineProperty实现响应式
    b. 重写虚拟DOM的实现和Tree-Shaking
    c. …
   3)拥抱TypeScript
    a. Vue3可以更好的支持TypeScript
   4)新的特性
    a. Composition API(组合API)

  • setup配置
  • ref与reactive
  • watch与watchEffect
  • provide与inject
  •    ...

        b. 新的内置组件

  • Fragment
  • Teleport
  • Suspense
  •    ...

        c. 其他改变

  • 新的生命周期钩子
  • data 选项应始终被声明为一个函数
  • 移除keyCode支持作为 v-on 的修饰符
  •    ...

      2.创建Vue3.0工程
      A.使用 vue-cli 创建
       官方文档:https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create

    ### 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
    vue --version
    ### 安装或者升级你的@vue/cli
    npm install -g @vue/cli
    ### 创建
    vue create vue_test
    ### 启动
    cd vue_test
    npm run serve
    

      B.使用 vite 创建
       1)官方文档:https://v3.cn.vuejs.org/guide/installation.html#vite
        a. 什么是vite?—— 新一代前端构建工具
        b. 优势如下:

  • 开发环境中,无需打包操作,可快速的冷启动
  • 轻量快速的热重载(HMR)
  • 真正的按需编译,不再等待整个应用编译完成
  • ### 创建工程
    
    ## npm 6.x
    $ npm init vite@latest <project-name> --template vue  
    ### 如: npm init vite@latest vue3-study --template vue
    
    ## npm 7+,需要加上额外的双短横线
    $ npm init vite@latest <project-name> -- --template vue
    
    ### 使用 PNPM:
    pnpm create vite <project-name> -- --template vue
    ## pnpm create vite vite-app -- --template vue
    
    ### 进入工程目录
    cd <project-name>
    ### 安装依赖
    pnpm install
    ### 运行
    pnpm run dev
    

         vite里面导入vue模块要加后缀名,不然会报错
          import Demo from ‘./components/Demo.vue’
      C.命令行界面
       1)在安装了 Vite 的项目中,可以在 npm scripts 中使用 vite 可执行文件,或者直接使用 npx vite 运行它。下面是通过脚手架创建的 Vite 项目中默认的 npm scripts:

    {
      "scripts": {
        "dev": "vite", // 启动开发服务器,别名:`vite dev`,`vite serve`
        "build": "vite build", // 为生产环境构建产物
        "preview": "vite preview" // 本地预览生产构建产物
      }
    }
    

          可以指定额外的命令行选项,如 --port 或 --https。运行 npx vite --help 获得完整的命令行选项列表
      D.常用 Composition API
       1)官方文档: https://v3.cn.vuejs.org/guide/composition-api-introduction.html
      E.Composition API 的优势
       1)Options API 存在的问题
         使用传统OptionsAPI中,新增或者修改一个需求,就需要分别在data,methods,computed里修改
       2)Composition API 的优势
         可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起
      F.全局API的转移
        a. Vue 2.x 有许多全局 API 和配置
          例如:注册全局组件、注册全局指令等

    //注册全局组件
    Vue.component('MyButton', {
      data: () => ({
        count: 0
      }),
      template: '<button @click="count++">Clicked {{ count }} times.</button>'
    })
    
    //注册全局指令
    Vue.directive('focus', {
      inserted: el => el.focus()
    }
    

        b. Vue3.0中对这些API做出了调整:
          将全局的API,即:Vue.xxx调整到应用实例(app)上
    在这里插入图片描述
      G.其它改变
       1)data选项应始终被声明为一个函数
       2)过度类名的更改:
        a. Vue2.x写法

    .v-enter,
    .v-leave-to {
      opacity: 0;
    }
    .v-leave,
    .v-enter-to {
      opacity: 1;
    }
    

        b. Vue3.x写法

    .v-enter-from,
    .v-leave-to {
      opacity: 0;
    }
    
    .v-leave-from,
    .v-enter-to {
      opacity: 1;
    }
    

       3)移除keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes
       4)移除v-on.native修饰符
        a. 父组件中绑定事件

    <my-component
      v-on:close="handleComponentEvent"
      v-on:click="handleNativeClickEvent"
    />
    

        b. 子组件中声明自定义事件

    <script>
      export default {
        emits: ['close']
      }
    </script>
    

       5)移除过滤器(filter)
         过滤器虽然这看起来很方便,但它需要一个自定义语法,打破大括号内表达式是 “只是 JavaScript” 的假设,这不仅有学习成本,而且有实现成本!建议用方法调用或计算属性去替换过滤器
       6)…
      H.路径别名
       1)vite.config.ts

    import { resolve } from 'path';
    export default defineConfig({
      resolve: {
        // 配置别名
        alias: {
          '@': path.resolve(__dirname, './src'),
          '@c': path.resolve(__dirname, './src/components'),
          '@v': path.resolve(__dirname, './src/views'),
          '@h': path.resolve(__dirname, './src/hooks'),
          '@s': path.resolve(__dirname, './src/store'),
        },
      },
    });
    
    1.path模块需要 pnpm i @types/node -D
    
    2.tsconfig.node.json文件配置
    
    "compilerOptions": {
    
    "allowSyntheticDefaultImports": true
    
    },
    
    3.tsconfig.json文件配置
    
    "compilerOptions": {
    
    "baseUrl": "./",
    
    "paths": {
    
    "@/*": ["src/*"],
    
    "@h/*": ["src/hooks/*"],
    
    "@s/*": ["src/store/*"]
    
    },
    
    },
    
    解决文件路径红线
    

      I.导入ts文件
       1)当在main.ts文件导入别名的时候报错导入路径不能以“.ts”扩展名结束。考虑改为导入“./utils/Bus.js”
       2)解决方案
         既然不允许用扩展名,那么我省略扩展名好了
          vite.config.ts

    export default defineConfig({
      resolve: {
        alias: {
          '@': path.resolve(__dirname, 'src')
        },
        extensions: ['.ts', '.js', '.mjs', '.jsx', '.tsx', '.json']
      }
    })
    

         这样,扩展名就不需要写了
      J.使用Scss
       1)首先用pnpm i sass -D
       2)在style标签中使用lang='scss’就可以了
       3)注意
         如果像这样,定义了很多scss文件
    在这里插入图片描述
         直接引入是找不到这些文件里面定义的内容的
         会有这样的报错
    在这里插入图片描述

         解决方法
        在src目录中定义sytle.scss文件
    在这里插入图片描述

          style.scss

    @import '@/styles/reset.scss';
    @import '@/styles/variables.scss';
    @import '@/styles/mixins.scss';
    

          然后在vite.config.ts中配置

    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    
    export default defineConfig({
      // 使用scss
      css: {
        preprocessorOptions: {
          scss: {
            additionalData: `@import "./src/style.scss";`
          },
        },
      },
    })
    

     F22.Vuex(K130-K136)

      1.理解 Vuex
      A.Vuex 是什么
       1)概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对Vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信
      B.什么时候使用 Vuex
       1)多个组件依赖于同一状态
       2)来自不同组件的行为需要变更同一状态
      C.原理图
    在这里插入图片描述

      2.搭建Vuex环境
       1)下载安装 pnpm add vuex@3
       2)创建文件:src/store/index.js

    import Vue from 'vue'
    import Vuex from 'vuex'	// 引入Vuex
    
    Vue.use(Vuex)	// 应用Vuex插件
    
    const actions = {}		// 准备actions——用于响应组件中的动作
    const mutations = {}	// 准备mutations——用于操作数据(state)
    const state = {}			// 准备state——用于存储数据
    
    // 创建并暴露store
    export default new Vuex.Store({
    	actions,
    	mutations,
    	state,
    })
    

       3)在main.js中创建vm时传入store配置项

    import Vue from 'vue'
    import App from './App.vue'
    import store from './store'	// 引入store
    
    Vue.config.productionTip = false
    
    new Vue({
    	el: '#app',
    	render: h => h(App),
    	store,	// 配置项添加store
    	beforeCreate() {
    		Vue.prototype.$bus = this
    	}
    })
    

      3.使用Vuex编写
       1)初始化数据、配置actions、配置mutations,操作文件store.js

    import Vue from 'vue'
    import Vuex from 'vuex'	// 引入Vuex
    
    Vue.use(Vuex)	// 应用Vuex插件
    
    // 准备actions——用于响应组件中的动作
    const actions = {
    	/* jia(context,value){
    		console.log('actions中的jia被调用了')
    		context.commit('JIA',value)
    	},
    	jian(context,value){
    		console.log('actions中的jian被调用了')
    		context.commit('JIAN',value)
    	}, */
    	jiaOdd(context,value){	// context 相当于精简版的 $store
    		console.log('actions中的jiaOdd被调用了')
    		if(context.state.sum % 2){
    			context.commit('JIA',value)
    		}
    	}
    }
    // 准备mutations——用于操作数据(state)
    const mutations = {
    	JIA(state,value){
    		console.log('mutations中的JIA被调用了')
    		state.sum += value
    	},
    	JIAN(state,value){
    		console.log('mutations中的JIAN被调用了')
    		state.sum -= value
    	}
    }
    // 准备state——用于存储数据
    const state = {
    	sum:0 //当前的和
    }
    
    // 创建并暴露store
    export default new Vuex.Store({
    	actions,
    	mutations,
    	state,
    })
    

       2)组件中读取vuex中的数据:$store.state.sum
       3)组件中修改vuex中的数据: $store.dispatch('action中的方法名',数据) $store.commit('mutations中的方法名',数据)
         备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit
        src/components/Count.vue

    <template>
    	<div>
    		<h1>当前求和为:{{ $store.state.sum }}</h1>
    		<select v-model.number="n">
    			<option value="1">1</option>
    			<option value="2">2</option>
    			<option value="3">3</option>
    		</select>
    		<button @click="increment">+</button>
    		<button @click="decrement">-</button>
    		<button @click="incrementOdd">当前求和为奇数再加</button>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'Count',
    		data() {
    			return {
    				n:1, //用户选择的数字
    			}
    		},
    		methods: {
    			increment(){
                    // commit 是操作 mutations
    				this.$store.commit('JIA',this.n)
    			},
    			decrement(){
                    // commit 是操作 mutations
    				this.$store.commit('JIAN',this.n)
    			},
    			incrementOdd(){
                    // dispatch 是操作 actions
    				this.$store.dispatch('jiaOdd',this.n)
    			},
    		}
    	}
    </script>
    
    <style lang="css">button{margin-left: 5px;}</style>
    

      4.getters 配置项
       1)概念:当state中的数据需要经过加工后再使用时,可以使用getters加工
       2)在store.js中追加getters配置

    ......
    
    const getters = {
    	bigSum(state){
    		return state.sum * 10
    	}
    }
    
    // 创建并暴露store
    export default new Vuex.Store({
    	......
    	getters
    })
    

       3)组件中读取数据:$store.getters.bigSum
      5.四个map方法的使用
       1)mapState方法:用于帮助我们映射state中的数据为计算属性

    computed: {
        //借助mapState生成计算属性:sum、school、subject(对象写法)
         ...mapState({sum:'sum',school:'school',subject:'subject'}),
             
        //借助mapState生成计算属性:sum、school、subject(数组写法)
        ...mapState(['sum','school','subject']),
    },
    

       2)mapGetters方法:用于帮助我们映射getters中的数据为计算属性

    computed: {
        //借助mapGetters生成计算属性:bigSum(对象写法)
        ...mapGetters({bigSum:'bigSum'}),
    
        //借助mapGetters生成计算属性:bigSum(数组写法)
        ...mapGetters(['bigSum'])
    },
    

       3)mapActions方法:用于帮助我们生成与actions对话的方法,即:包含$store.dispatch(xxx)的函数

    methods:{
        //靠mapActions生成:incrementOdd、incrementWait(对象形式)
        ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
    
        //靠mapActions生成:incrementOdd、incrementWait(数组形式)
        ...mapActions(['jiaOdd','jiaWait'])
    }
    

       4)mapMutations方法:用于帮助我们生成与mutations对话的方法,即:包含$store.commit(xxx)的函数

    methods:{
        //靠mapActions生成:increment、decrement(对象形式)
        ...mapMutations({increment:'JIA',decrement:'JIAN'}),
        
        //靠mapMutations生成:JIA、JIAN(对象形式)
        ...mapMutations(['JIA','JIAN']),
    }
    

         备注:mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象

    <template>
    	<div>
    		<h1>当前求和为:{{ sum }}</h1>
    		<h3>当前求和的10倍为:{{ bigSum }}</h3>
    		<h3>我是{{ name }},我在{{ school }}学习</h3>
    		<select v-model.number="n">
    			<option value="1">1</option>
    			<option value="2">2</option>
    			<option value="3">3</option>
    		</select>
    		<button @click="increment(n)">+</button>
    		<button @click="decrement(n)">-</button>
    		<button @click="addOdd(n)">当前求和为奇数再加</button>
    		<button @click="addWait(n)">等一等再加</button>
    	</div>
    </template>
    
    <script>
    	import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'	
    
    	export default {
    		name: 'Count',
    		data() {
    			return {
    				n:1, //用户选择的数字
    			}
    		},
      computed: {		
    			...mapState(['sum','school','name']),
    			...mapGetters(['bigSum'])
    		},
    		methods: {
    			...mapMutations({increment:'ADD', decrement:'SUBTRACT'}),
    			...mapActions(['addOdd', 'addWait'])
    		},
    	}
    </script>
    
    <style>
    	button{
    		margin-left: 5px;
    	}
    </style>
    

      6.模块化+命名空间
       1)目的:让代码更好维护,让多种数据分类更加明确
       2)修改store.js 为了解决不同模块命名冲突的问题,将不同模块的namespaced: true,之后在不同页面中引入getter、actions、mutations时,需要加上所属的模块名

    const countAbout = {
      namespaced:true,//开启命名空间
      state:{x:1},
      mutations: { ... },
      actions: { ... },
      getters: {
        bigSum(state){
           return state.sum * 10
        }
      }
    }
    
    const personAbout = {
      namespaced:true,//开启命名空间
      state:{ ... },
      mutations: { ... },
      actions: { ... }
    }
    
    const store = new Vuex.Store({
      modules: {
        countAbout,
        personAbout
      }
    })
    

       3)开启命名空间后,组件中读取state数据:

    //方式一:自己直接读取
    this.$store.state.personAbout.list
    //方式二:借助mapState读取:
    ...mapState('countAbout',['sum','school','subject']),
    

       4)开启命名空间后,组件中读取getters数据:

    //方式一:自己直接读取
    this.$store.getters['personAbout/firstPersonName']
    //方式二:借助mapGetters读取:
    ...mapGetters('countAbout',['bigSum'])
    

       5)开启命名空间后,组件中调用dispatch

    //方式一:自己直接dispatch
    this.$store.dispatch('personAbout/addPersonWang',person)
    //方式二:借助mapActions:
    ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
    

       6)开启命名空间后,组件中调用commit

    //方式一:自己直接commit
    this.$store.commit('personAbout/ADD_PERSON',person)
    //方式二:借助mapMutations:
    ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
    

     F22.vue3自动导入配置(K137-K143)

      1.自动导入组件库组件
       1)unplugin-vue-components
    在这里插入图片描述

       2)安装
         pnpm install unplugin-vue-components -D
          然后将下面的代码添加到 Vite 的配置文件
       3)Vite配置

    // vite.config.js
    import { defineConfig } from 'vite'
    import Components from 'unplugin-vue-components/vite'
    import {
      ElementPlusResolver,
      AntDesignVueResolver,
      VantResolver,
      HeadlessUiResolver,
      ElementUiResolver
    } from 'unplugin-vue-components/resolvers'
    
    export default defineConfig({
      plugins: [
        Components({
          // ui库解析器,也可以自定义
          resolvers: [
            ElementPlusResolver(),
            AntDesignVueResolver(),
            VantResolver(),
            HeadlessUiResolver(),
            ElementUiResolver()
          ]
        })
      ]
    })
    

       4)插件会生成一个ui库组件以及指令路径components.d.ts文件,详情看这个vue3的issue types(defineComponent): support for expose component types

    // components.d.ts
    
    // generated by unplugin-vue-components
    // We suggest you to commit this file into source control
    // Read more: https://github.com/vuejs/vue-next/pull/3399
    
    declare module 'vue' {
      export interface GlobalComponents {
        ElAside: typeof import('element-plus/es')['ElAside']
        ElButton: typeof import('element-plus/es')['ElButton']
        ElContainer: typeof import('element-plus/es')['ElContainer']
        ElDropdown: typeof import('element-plus/es')['ElDropdown']
        ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
        ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
        ElHeader: typeof import('element-plus/es')['ElHeader']
        ElIcon: typeof import('element-plus/es')['ElIcon']
        ElMain: typeof import('element-plus/es')['ElMain']
        ElMenu: typeof import('element-plus/es')['ElMenu']
        ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
        ElResult: typeof import('element-plus/es')['ElResult']
      }
    }
    
    export { }
    

          想了解其他的打包工具(Rollup, Vue CLI),请参考 unplugin-vue-components
       5)自动导入自己的组件
         直接写组件名即可,插件会帮你引入进来 注意别重名

    // vite.config.js
    import { defineConfig } from 'vite'
    import Components from 'unplugin-vue-components/vite'
    
    export default defineConfig({
      plugins: [
        Components({
          // 指定组件位置,默认是src/components
          dirs: ['src/components', 'src/views'],
          // ui库解析器
          // resolvers: [ElementPlusResolver()],
          extensions: ['vue'],
          // 配置文件生成位置
          dts: 'src/components.d.ts'
        })
      ]
    })
    

          插件会生成一个自己组件路径的components.d.ts文件,详情再看这个vue3的issue types(defineComponent): support for expose component types

    // components.d.ts
    
    // generated by unplugin-vue-components
    // We suggest you to commit this file into source control
    // Read more: https://github.com/vuejs/vue-next/pull/3399
    
    declare module 'vue' {
      export interface GlobalComponents {
        BaseFilter: typeof import('./components/Common/BaseFilter.vue')['default']
        BaseHeader: typeof import('./components/Common/BaseHeader.vue')['default']
        BasePagination: typeof import('./components/Common/BasePagination.vue')['default']
        BaseSidebar: typeof import('./components/Common/BaseSidebar.vue')['default']
        BaseTags: typeof import('./components/Common/BaseTags.vue')['default']
        BaseTitle: typeof import('./components/Common/BaseTitle.vue')['default']
      }
    }
    
    export { }
    

      2.自动导入Vue 函数和自己的公用函数
      A.自动导入Vue 函数
       1)自动导入vue3的hooks,借助unplugin-auto-import/vite这个插件
         支持vue, vue-router, vue-i18n, @vueuse/head, @vueuse/core等自动引入
       2)安装

    pnpm i -D unplugin-auto-import
    

       3)Vite配置

    // vite.config.js
    import { defineConfig } from 'vite'
    import AutoImport from 'unplugin-auto-import/vite'
    
    export default defineConfig({
      plugins: [
        AutoImport({
          // Auto import functions from Vue, e.g. ref, reactive, toRef...
          // 自动导入 Vue 相关函数,如:ref, reactive, toRef 等
          imports: ['vue', 'vue-router', ,'vue-i18n', '@vueuse/head', '@vueuse/core',],
          // 可以选择auto-import.d.ts生成的位置,使用ts建议设置为'src/auto-import.d.ts'
           dts: 'src/auto-import.d.ts'
            
        })
      ]
    })
    

       4)原理: 安装的时候会自动生成auto-imports.d文件(默认是在根目录)

    // Generated by 'unplugin-auto-import'
    // We suggest you to commit this file into source control
    declare global {
      const ref: typeof import('vue')['ref']
      const reactive: typeof import('vue')['reactive']
      const computed: typeof import('vue')['computed']
      const createApp: typeof import('vue')['createApp']
      const watch: typeof import('vue')['watch']
      const customRef: typeof import('vue')['customRef']
      const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
      .
      .
      .
    }
    export {}
    

       5)可以选择auto-import.d.ts生成的位置,使用ts建议设置为src/auto-import.d.ts
          可以选择auto-import.d.ts生成的位置,使用ts建议设置为src/auto-import.d.ts
      B.自动导入自己的公用函数
       1)默认导入axios,分别导入pinia的storeToRefs

    AutoImport({
          // Auto import functions from Vue, e.g. ref, reactive, toRef...
          // 自动导入 Vue 相关函数,如:ref, reactive, toRef 等
          imports: [
            'vue',
            'vue-router',
            {
              axios: [
                // default imports
                ['default', 'axios'], // import { default as axios } from 'axios',
              ],
               pinia: ['storeToRefs'],
                // import { storeToRefs } from 'pinia'
            },
            '@vueuse/core',
          ],
        }),
    

       2)自动导入自己定义的函数

      AutoImport({
        // Auto import for module exports under directories
        // by default it only scan one level of modules under the directory
        dirs: ['./src/utils'],
        // 可以选择auto-import.d.ts生成的位置,使用ts建议设置为'src/auto-import.d.ts'
        dts: 'src/auto-import.d.ts',
        // 在vue模板中使用
        vueTemplate: true,
      }),
    

         观察auto-import.d.ts文件

    export {}
    declare global {
      const axios: typeof import('axios')['default']
      const bus: typeof import('./utils/bus')['bus']
      const diffDays: typeof import('./utils/date')['diffDays']
      const formatDate: typeof import('./utils/date')['formatDate']
      const http: typeof import('./utils/service')['http']
      const isDark: typeof import('./utils/dark')['isDark']
    }
    

      3.自动导入组件库样式

    import { createStyleImportPlugin, ElementPlusResolve  } from 'vite-plugin-style-import';
    
    plugins: [vue(),
     //按需导入element-plus的css样式
         createStyleImportPlugin({
          resolves: [ElementPlusResolve()],
        }),
    ], //查看 插件 API 获取 Vite 插件的更多细节 https://www.vitejs.net/guide/api-plugin.html
    

      4.自动导入icon
       1)安装依赖

    # @iconify-json/ep 是 Element Plus 的图标库
    pnpm i -D unocss @iconify-json/ant-design
    

       2)修改 vite.config.ts 配置

    // vite.config.ts
    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    import Unocss from 'unocss/vite'
    import {
      presetAttributify,
      presetIcons,
      presetUno,
      transformerDirectives,
      transformerVariantGroup,
    } from 'unocss';
    
    export default defineConfig({
      plugins: [
        vue(),
    
        // 添加以下配置
        Unocss({
          presets: [
            presetUno(),
            presetAttributify(),
            presetIcons({
              scale: 1.2,
              warn: true,
            }),
          ],
          transformers: [transformerDirectives(), transformerVariantGroup()],
        })
      ]
    })
    

       3)修改 main.ts

    // 在 main.ts 里添加以下代码
    import 'uno.css'
    

       4)使用

    // svg图片
    <i
        class="i-ant-design-picture-filled w-330px h-240px"
    />
    // 图标字体
    <i
        i="ant-design-picture-filled"
    />
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值