Vue最佳實踐和實用技巧

PHP定製開發發表於2022-10-08

1.props限制和透傳

crmeb內自定義限制

props: {
    size: {
        // 自定義驗證函式
        validator: (val) => {
            return ["small", "medium", "large"].includes(val);
        },
    }}複製程式碼

這個驗證函式接受一個 prop值,驗證並返回 true 或 false
透傳屬性

<!-- 此元件為二次封裝的中間元件 --><template>
  <MyComponent v-bind="$attrs"/></template><script> 
  export default { 
    // $attrs 中的所有屬性不自動繼承到元件的根元素上
    inheritAttrs: false,
  }</script>複製程式碼
  • $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->

<MyComponent v-bind="$attrs" v->

注意:  listeners元件例項屬性在Vue3.x被取消,其監聽都整合到了 l i s t e n ers 元件例項屬性在 V u e 3. x 被取消,其監聽都整合到了attrs屬性上
單個slot透傳

<About>
    <template #about>
        <slot name="about" />
    </template></About>複製程式碼

多個slot透傳

<template #[slotName] v-for="(slot, slotName) in $slots" >
    <slot :name="slotName"/></template>複製程式碼

多個slot透傳作用域插槽

<template #[slotName]="slotProps" v-for="(slot, slotName) in $slots" >
    <slot :name="slotName" v-bind="slotProps"/></template><!-- Vue2則需要將v-for裡面迴圈的$slots改成$scopedSlots -->複製程式碼

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更好擴充套件

<template>
  <div>
    <div v-if="$slots.default">
      <slot />
    </div>
    <div v-if="$slots.slotA">
      <slot name="slotA"/>
    </div>
  </div></template>複製程式碼

4.檢測點選是否發生在元素內部

window.addEventListener('mousedown', e => {
  // 獲取被點選的元素
  const clickedEl = e.target;
  // `targetEl` 為檢測的元素
  if (targetEl.contains(clickedEl)) {
    // 在"targetEl"內部點選
  } else {
    // 在"targetEl"之外點選
  }});複製程式碼

5.動態元件和遞迴元件

動態元件:tab切換的時候可使用動態元件動態載入並快取提供動效

<transition>
  <keep-alive>
    <!-- :is值必須是全域性或者區域性註冊過的元件 -->
    <component :is="currentTab"></component>
  </keep-alive></transition>複製程式碼

遞迴元件:模板裡面自己自己,注意需要設定條件退出,不然會無限渲染,適合巢狀選單,樹形控制元件等

<div v-if="item.children">
  {{ tree.label }}
  <!-- 遞迴呼叫自身 -->
  <tree v-for="(item, index) in tree.children" :tree="item" :key="index"></tree></div><script>
  export default {
    // 定義name,以使元件內部遞迴呼叫
    name: 'tree',
    // 接收外部傳入的值
    props: {
      tree: {
        type:Array,
        default: () => []
      }
    }
  }</script>複製程式碼

6.nextTick

  • 在下次 DOM 更新迴圈結束之後執行延遲迴調
  • 我們可以在修改資料後立即使用此方法獲取最新的DOM
mounted(){
  this.$nextTick(() => {
    this.$refs.inputs.focus(); //透過 $refs 獲取dom 並繫結 focus 方法
  })}複製程式碼

7.簡化 :class 和 v-if 與邏輯

<div :class="
			$route.name === 'Home' ||
			$route.name === 'Gallery' ||
			$route.name === 'Profile'
				? 'classOnlyOnThesePages'
				: ''
		"
	></div>複製程式碼

直接最佳寫法如下:

<div :class="{
			classOnlyOnThesePages: ['Home', 'Gallery', 'Profile'].includes(
				$route.name
			),
		}"
	></div>複製程式碼

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 方法來控制 router-view 的顯示隱藏
<template>
	<div id="app">
		<router-view v-if="isActive" />
	</div></template><script>export default {
	name: "App",
  // provider給下層元件重刷的方法
	provide() {
		return {
			reload: this.reload,
		};
	},
	data: {
      isActive: true,
	},
	method: {
		reload() {
			this.isActive = false;
			this.$nextTick(() => {
				this.isActive = true;
			});
		},
	},};</script>複製程式碼

需要的頁面可注入該方法使用

<script>export default {
	inject: ["reload"],
	methods: {
		refresh() {
			this.reload();
		},
	},};</script>複製程式碼

或者直接使用v-if操作該元件

<template>
	<div v-if="isShow"></div></template><script>export default {
	data() {
		return {
			isShow: true,
		};
	},
	method: {
		refresh() {
			this.isShow = false;
			this.$nextTick(() => {
				this.isShow = true;
			});
		},
	},};</script>複製程式碼

或者藉助Vue的diff演算法,我們給元素設定一個唯一的Key值然後去改變它

<template>
	<div :key="keyValue"></div></template><script>export default {
	data() {
		return {
			keyValue: 0,
		};
	},
	method: {
		refresh() {
			this.keyValue++;
		},
	},};</script>複製程式碼

10.元件封裝原則

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

  • 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 標籤可以在模板內的任何地方使用,可以減少實際巢狀層級,更簡化程式碼邏輯

<template>
    <div class="card">
        <h3>
            {{ title }}
        </h3>
        <h4 v-if="isShow" class="card-desc">
            {{ description }}
        </h4>
        <div v-if="isShow">
            <slot />
        </div>
        <Home v-if="isShow" />
    </div></template>複製程式碼

上面程式碼v-if邏輯分組後:

<template>
    <div class="card">
        <h3>
            {{ title }}
        </h3>
        <template v-if="isShow">
            <h4 class="card-desc">
                {{ description }}
            </h4>
            <div>
                <slot />
            </div>
            <Home />
        </template>
    </div></template>複製程式碼

13.在 v-for 中解構

在模板中使用 v-for 遍歷輸出資料,可以使用解構語法

<div
			v-for="{ id, user } in [
				{ id: 1, user: 'yun' },
				{ id: 2, user: 'mu' },
			]"
			:key="id"
		>
			{{ user }}</div>複製程式碼

14.全域性和區域性style混合及樣式穿透

<style>
  /* 全域性有效 */
  .content p {
    font-size: 12px;
  }</style>
  <style scoped>
  /* 只在該元件內有效 */
  .content {
    background: green;
  }</style>複製程式碼

有時候我們想跳出scoped這個限定作用域,更改子元件的樣式但不會影響全域性樣式,我們就可以使用深度選擇器來完成

<style scoped>:deep(.ant-card-head-title){
    background: green;
  }</style>複製程式碼

上面程式碼會被解析為

[data-v-e44d851a] .ant-card-head-title {
    background: green;}複製程式碼

注意:vue版本和預處理不同,深度選擇器的寫法也會不同,靈活使用即可
15.借用props型別
當我們當前元件使用到了Card元件

<Card :type="Mytype" :color="Mycolor">複製程式碼

其中的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
  },};


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70021881/viewspace-2917235/,如需轉載,請註明出處,否則將追究法律責任。

相關文章