标签: Vue

  • Vue3自定义组件名字

    在使用setup语法糖的时候没办法直接定义组件的名字,有两种解决方法

    写两个script标签

    <script lang="ts">
    import { defineComponent, onMounted } from 'vue'
    //script1:用来定义name
    export default defineComponent({
      name: '自定义name'
    })
    </script>
    
    <script lang="ts" setup>
     //script2:用来定义setup语法糖
    </script>

    使用vite-plugin-vue-setup-extend

    安装
    npm i vite-plugin-vue-setup-extend -D
    配置vite.config.js
    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    // 引入vite-plugin-vue-setup-extend
    import VueSetupExtend from 'vite-plugin-vue-setup-extend'
    
    export default defineConfig({
      // 配置
        plugins: [vue(), VueSetupExtend()],
    })
    使用
    <script lang="ts" setup name="自定义name">
    // 使用vite-plugin-vue-setup-extend插件
    </script>

    https://blog.csdn.net/SunFlower914/article/details/126579209

  • Vue+ts使用animate.css

    安装

    npm install animate.css --save
    or
    yarn add animate.css

    在main.ts中引入

    import { createApp } from 'vue'
    import App from './App.vue'
    // 引入animate.css
    import 'animate.css'
    
    createApp(App).mount('#app')

    此时会提示找不到模块“animate.css”或其相应的类型声明

    解决方法

    找到 src/vite-env.d.ts(老版本Vite为shims-vue.d.ts)

    添加下面代码

    declare module 'animate.css' 
    // 声明animate.css的类型,否则引入animate.css会报错,提示找不到animate.css模块

    使用

    组件中使用animate.css,需要注意的是,样式class类名,必须加上animate__animated,其次则是要引入动画的class类名,如animate__slideInUp

    <template>
      <div class="content-box animate__animated animate__slideInUp">
        滑动进入特效演示
      </div>
    </template>

    修改动画属性

    方法一:直接通过动画class类名animated修改

    .animated {
        -webkit-animation-duration: 1s; 
        animation-duration: 2s; // 动画执行时间
        -webkit-animation-fill-mode: both;
        animation-fill-mode: both;
    }

    方法二:修改指定动画的属性

    .animate__slideInUp {
        -webkit-animation-duration: 1s; 
        animation-duration: 2s; // 动画执行时间
        -webkit-animation-fill-mode: both;
        animation-fill-mode: both;
    }

    方法三:在要执行动画的div设置stye

    <div 
        class="content-box animate__animated animate__slideInUp"
        :style="{animationDuration: '500ms'}"
        >
    </div>

    vue+ts或者react+ts如何使用animate.css

  • Vite配置preprocessorOptions全局引入less

    css.preprocessorOptions.less.additionalData

    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [ vue() ],
      css: {
        preprocessorOptions: {
          less: {
            additionalData: `
              @import "@/assets/styles/variables.less";
              @import "@/assets/styles/mixins.less";
            `
          }
        }
      }
    })
  • Vue打包优化

    打包优化

    1.异步组件,路由按需加载 (解决首屏加载过慢)

    component: () => import('@/views/Home/index')

    2.排除一些依赖包,将依赖包(不太会变化的包,如Vue、Element UI等)存在cdn上,可以加快打包速度,也可以让不同地域的用户在请求资源时得到更快的响应

    webpack排除打包

    找到 vue.config.js,在configureWebpack配置项中添加externals 选择填入不打包的依赖包

    configureWebpack: {
      ...
      externals: {
        // key(要排除的包名), value(引入的CDN包的全局变量名)
        'vue': 'Vue',
        'element-ui': 'ELEMENT',
        ...
      },
    }

    此时这些包已经被排除打包了,因为缺少这些包,项目无法正常运行,接下来还需要配置CDN

    vue.config.js

    const cdn = {
      css: [
        'https://unpkg.com/element-ui/lib/theme-chalk/index.css' // element-ui css 样式表
      ],
      js: [
        // vue must at first!
        'https://unpkg.com/vue/dist/vue.js', // vuejs
        'https://unpkg.com/element-ui/lib/index.js', // element-ui js
        ...
      ]
    }

    开发环境没有必要使用CDN来引入包,可以通过环境变量来判断是否使用CDN

    const isProduction = process.env.NODE_ENV === 'production' // 判断是否是生产环境
    
    let externals = {}
    let cdn = { css: [], js: [] }
    
    if (isProduction) {
      externals = {
        // key(要排除的包名), value(引入的CDN包的全局变量名)
        'vue': 'Vue',
        'element-ui': 'ELEMENT',
        ...
      }
      cdn = {
        css: [
          'https://unpkg.com/element-ui/lib/theme-chalk/index.css' // element-ui css 样式表
        ],
        js: [
          // vue must at first!
          'https://unpkg.com/vue/dist/vue.js', // vuejs
          'https://unpkg.com/element-ui/lib/index.js', // element-ui js
          ...
        ]
      }
    } 
    
    
    ···
    // 使用externals
    module.exports = {
      configureWebpack: {
      ...
      externals: externals,
     }
    }

    将CDN文件链接注入到模板

    https://cli.vuejs.org/zh/guide/webpack.html#修改插件选项

    chainWebpack(config) {
      // it can improve the speed of the first screen, it is recommended to turn on preload
      config.plugin('preload').tap(() => [
        {
          rel: 'preload',
          // to ignore runtime.js
          // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
          fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
          include: 'initial'
        }
      ])
    
      // 注入cdn变量 (打包时会执行)   
      //https://cli.vuejs.org/zh/guide/webpack.html#修改插件选项
      config.plugin('html').tap(args => {
        args[0].cdn = cdn // 配置cdn给插件
        return args
      })
      ...
    }

    找到 public/index.html

    <head>
      <!-- 引入CSS -->
      <% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
        <link rel="stylesheet" href="<%=css%>">
      <% } %>
    </head>
    
    <!-- 引入JS -->
    <% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
      <script src="<%=js%>"></script>
    <% } %>

    打包

    yarn build
  • ElementUI配合Vue-I18n实现多语言切换

    安装

    npm i vue-i18n element-ui

    引入

    https://element.eleme.cn/#/zh-CN/component/i18n

    src目录下新建lang/index.js

    import Vue from 'vue'
    import VueI18n from 'vue-i18n' // 引入国际化的插件包
    import elementEN from 'element-ui/lib/locale/lang/en' // 引入饿了么的英文包
    import elementZH from 'element-ui/lib/locale/lang/zh-CN' // 引入饿了么的中文包
    import customZH from './zh' // 引入自定义中文包
    import customEN from './en' // 引入自定义英文包
    
    Vue.use(VueI18n)
    
    const messages = {
      en: {
        message: 'hello',
        ...enLocale // 或者用 Object.assign({ message: 'hello' }, enLocale)
      },
      zh: {
        message: '你好',
        ...zhLocale // 或者用 Object.assign({ message: '你好' }, zhLocale)
      }
    }
    
    export default new VueI18n({
      locale: 'en', // set locale
      messages, // set locale messages
    })

    main.js

    ···
    // 配置ElementUI的中英切换逻辑
    Vue.use(ElementUI, {
      i18n: (key, value) => i18n.t(key, value)
    })
    
    new Vue({
      el: '#app',
      ···
      i18n,
      render: h => h(App)
    })

    使用

    当我们全局注册i18n的时候,每个组件都会拥有一个$t的方法, $t 方法会被挂载到 vue 原型上

    它会根据传入的key,自动的去寻找当前语言的文本, $t('title')

    <div>
      {{ $t('title') }}
      <span>{{ $t('hello') }}</span>
    </div>

    语言切换

    this.$i18n.locale = 'en'

    Vue I18n https://kazupon.github.io/vue-i18n/zh/

  • 利用vue-print-nb实现打印功能

    安装

    Vue2

    npm install vue-print-nb --save

    Vue3

    npm install vue3-print-nb --save

    引入

    import Print from 'vue-print-nb'
    Vue.use(Print)

    给要打印的盒子指定 id

    <div id="print">

    使用v-print指令的方式进行打印

    <button v-print="{ id: 'printbox' }">打印</button>

    注意点

    • Callback函数中this指向当前print object对象,that返回Vue对象
    • 不需要页眉页脚可以在打印弹窗页面的更多设置里面取消选择
    • 不设置popTitle参数页眉标题为undifined
    • popTitle参数为空时,页眉标题默认为Document Title

    利用vue-print-nb实现打印功能

    vue-print-nb – npm

  • Vue使用NProgress

    NProgress是页面跳转是出现在浏览器顶部的进度条
    官网:http://ricostacruz.com/nprogress/
    github:https://github.com/rstacruz/nprogress

    安装

    npm install --save nprogress 或者
    yarn add nprogress
    
    //用法
    NProgress.start();
    NProgress.done();

    使用

    //导入
    import NProgress from 'nprogress'
    import 'nprogress/nprogress.css'
    
    router.beforeEach((to, from, next) => {
      NProgress.start()
      next()
    })
    
    router.afterEach(() => {
      NProgress.done()
    })

    注意

    ···
    next('/login')
    NProgress.done()
    ···

    被next拦截走的, 不会自动关闭, 因为没有进入到 afterEach, 需要手动关闭

    Vue使用NProgress

  • Vue虚拟DOM与diff算法

    就地复用

    Vue会尽可能的就地(同层级,同位置),对比虚拟dom,复用旧dom结构,进行差异化更新。

    虚拟DOM

    真实DOM

    • HTML渲染出来的DOM树
    • 每个标签都是树的节点
    • 每个节点拥有非常多的属性 由于真实DOM的属性过多,导致对比差异会消耗过多的性能,且有很多无需遍历对比的属性,这样效率很低。

    虚拟DOM

    本质是JS对象,保存渲染真实DOM时的必要属性。

    <template>
    <div id="app">
      <h1 class="title">标题</h1>
    </div>
    </template>
    
    <script>
     const virtualDOM = {
       type:'div',
       attributes:[{id:'app'}],
       children:[{
         type:'h1',
         attributes:[{class:"title"}],
         text:'标题'
       }]
     }
    </script>
    渲染过程
    1. template渲染成虚拟DOM
    2. 根据虚拟DOM渲染成真实的DOM
    数据发生更新
    1. 重新生成一份新的虚拟DOM
    2. 对比新的虚拟DOM和旧的虚拟DOM,找到不同的地方
    3. 最后统一更新真实的DOM
    虚拟DOM的作用

    可以在内存中创建虚拟DOM,快速比较变化的部分, 然后给真实DOM打补丁(更新)

    虚拟DOM总结

    虚拟DOM相比真实DOM只保留了渲染时必要的属性,可以更高效地对比DOM新旧差异,进行差异化更新。

    diff算法

    虚拟DOM内部的比对过程称为diff算法

    策略一

    先同层级根元素比较,如果根元素变化,那么不考虑复用,整个dom树删除重建

    策略二

    对比同级兄弟元素时,默认按照下标进行对比复用。如果数组顺序没有发生改变,性能是高效的。

    如果数组的顺序发生了变化,性能并不高

    策略三

    同级兄弟元素,在设置了key后,会让相同key的元素进行对比。

    key必须是字符串或者数字,且必须唯一

    (尽量不用遍历的索引作为key,参考策略二中数组的顺序发生变化)

    总结

    • 设置了key在DOM更新时会按照相同的key进行新旧元素比较(不设置则默认为索引)
    • 目的:提高更新时的性能
    • key必须是字符串或者数字,且必须唯一
  • Vue使用Element UI控制台报错

    Vue使用Element UI控制台报错

    [Violation] Added non-passive event listener to a scroll-blocking 'touchmove' event.

    解决

    1、npm i default-passive-events -S

    2、main.js中加入:import 'default-passive-events'

    [Violation] Added non-passive event listener to a scroll-blocking ‘touchmove’ event._zlting~的博客-CSDN博客

  • Vue项目history模式下Nginx配置

    location /
      {
      try_files $uri $uri/ /index.html?$args;
      }