Vue最佳实践和实用技巧

1.props限制和透传

crmeb内自定义限制

props: {
    size: {
        // 自定义验证函数
        validator: (val) => {
            return ["small", "medium", "large"].includes(val);
        },
    }}复制代码

这个验证函数接受一个 prop值,验证并返回 true 或 false
透传属性

复制代码
  • $attrs包含所有透传过来的对象,除显式声明接受的props、emits、slots
  • 如不希望透传下去某些属性,可使用useAttrs()
const attrs = useAttrs();const filteredAttrs = computed(() => {
  return { ...attrs, style: undefined };});复制代码

$attrs还可与 listeners搭配使用,` l i s t e n ers 搭配使用, listeners`包含了父组件传递的事件(不包含.native修饰器),它可以通过v->

注意:  listeners组件实例属性在Vue3.x被取消,其监听都整合到了 l i s t e n ers 组件实例属性在 V u e 3. x 被取消,其监听都整合到了attrs属性上
单个slot透传


    
        
    复制代码

多个slot透传


    复制代码

多个slot透传作用域插槽


    复制代码

2.require.context()和import.meta.glob()批量引入文件

  • webpack统一导入相同路径下的多个组件的方法
const path = require("path");// 参数一:说明需要检索的目录,参数二:是否检索子目录,参数三::指定匹配文件名的正则表达式const files = require.context("./components", false, /\.vue$/);const modules = {};files.keys().forEach((key) => {
	const name = path.basename(key, ".vue");
	modules[name] = files(key).default || files(key);});复制代码
  • Vite 支持使用特殊的 import.meta.glob 函数从文件系统导入多个模块:
const modules = import.meta.glob('./src/*.js');// vite 转译上面后生成的代码const modules = {
  './src/foo.js': () => import('./src/foo.js'),
  './src/bar.js': () => import('./src/bar.js')}复制代码

3.有条件的渲染slot

  • 组件都有一个特殊的$slots对象,包含所有的插槽对象,结构如下:
const $slots = {
	"default": [{...}],
	"slotA": [{...}],
	"slotB": [{...}]}复制代码

我们可以使用v-if有条件的渲染slot更加合理,并且我们封装通用组件的时候最好预留个slot更好扩展

复制代码

4.检测点击是否发生在元素内部

window.addEventListener('mousedown', e => {
  // 获取被点击的元素
  const clickedEl = e.target;
  // `targetEl` 为检测的元素
  if (targetEl.contains(clickedEl)) {
    // 在"targetEl"内部点击
  } else {
    // 在"targetEl"之外点击
  }});复制代码

5.动态组件和递归组件

动态组件:tab切换的时候可使用动态组件动态加载并缓存提供动效


  
    
    
  复制代码

递归组件:模板里面自己自己,注意需要设置条件退出,不然会无限渲染,适合嵌套菜单,树形控件等


  {{ tree.label }}
  
  
复制代码

6.nextTick

  • 在下次 DOM 更新循环结束之后执行延迟回调
  • 我们可以在修改数据后立即使用此方法获取最新的DOM
mounted(){
  this.$nextTick(() => {
    this.$refs.inputs.focus(); //通过 $refs 获取dom 并绑定 focus 方法
  })}复制代码

7.简化 :class 和 v-if 与逻辑

复制代码

直接最佳写法如下:

复制代码

8.全局重用方法

class Utils {
	// 复制一段文字到剪切板
	copyToClipboard(text) {
		let copyText = document.createElement("input");
		document.body.appendChild(copyText);
		copyText.value = text;
		copyText.select();
		document.execCommand("copy");
		document.body.removeChild(copyText);
	}}export default new Utils();复制代码

我们可以抽离出来放在整个应用程序都能访问的地方
Vue2:

import Utils from "./utils/utils.js";// 设置全局方法Vue.prototype.$utils = Utils;复制代码

Vue3:

import Utils from "./utils/utils.js"; const app = createApp(App);// 设置全局方法app.config.globalProperties.$utils = Utils; app.mount("#app");复制代码接下来任何地方都能愉快的访问啦this.$utils.copyToClipboard(text);// Vue3 setupconst { proxy } = getCurrentInstance();proxy.$utils.copyToClipboard(text);复制代码

9.局部组件刷新

复制代码

需要的页面可注入该方法使用

复制代码

或者直接使用v-if操作该组件

复制代码

或者借助Vue的diff算法,我们给元素设置一个唯一的Key值然后去改变它

复制代码

10.组件封装原则

Vue组件的API主要包含三部分:props、event、slot

组件封装最好还应遵循单向数据流,传递的props仅仅做展示,如需修改,则应该重新初始化一份全新的响应式数据并将props深拷贝后作为初始值

11.错误(警告)处理

为 Vue 中的错误和警告提供自定义处理程序

// Vue 3const app = createApp(App);app.config.errorHandler = (err) => {
    console.error(err);};// Vue 2Vue.config.errorHandler = (err) => {
    console.error(err);};复制代码

12.使用template标签分组

template 标签可以在模板内的任何地方使用,可以减少实际嵌套层级,更简化代码逻辑

复制代码

上面代码v-if逻辑分组后:


    
复制代码

13.在 v-for 中解构

在模板中使用 v-for 遍历输出数据,可以使用解构语法

{{ user }}
复制代码

14.全局和局部style混合及样式穿透


  
  /* 只在该组件内有效 */
  .content {
    background: green;
  }复制代码

有时候我们想跳出scoped这个限定作用域,更改子组件的样式但不会影响全局样式,我们就可以使用深度选择器来完成

:deep(.ant-card-head-title){
    background: green;
  }复制代码

上面代码会被解析为

[data-v-e44d851a] .ant-card-head-title {
    background: green;}复制代码

注意:vue版本和预处理不同,深度选择器的写法也会不同,灵活使用即可
15.借用props类型
当我们当前组件使用到了Card组件

复制代码

其中的Mytype和Mycolor是我们通过props接收而来的

import Card from './Card.vue';export default {
  components: { Card },
  props: {
    Mytype: {
      type: String,
      required: true,
    },
    Mycolor: {
      type: String,
      default: "green",
    }
  },};复制代码

我们可以简写为

import Card from './Card.vue';const cardProps = {};Object.entries(Card.props).forEach(([key, value]) => {
	cardProps[`My${key}`] = value;});export default {
  components: { Card },
  props: {
  	...cardProps
  },};


请使用浏览器的分享功能分享到微信等