Mutation Directive

v-mutation是 Quasar 提供的一个 vue 指令,它提供了监听 DOM 树发生变化的能力,并在这些变化被触发时调用一个方法。

工作原理是使用了Mutation Observer API

Mutation API

Mutation API

类型
Function
说明
发生突变时调用的函数;强烈建议从 vue 组件作用域中引用它,否则指令更新周期将持续重新创建观察者严重影响性能

用法

请先阅读Mutation Observer API页面,有利于理解这个指令是如何工作的。

handler回调函数中有一个参数,参考:MutationRecord

捕获所有 Catch everything

v-mutation指令没有添加任何修饰符时,它会默认启用所有修饰符功能。(除了"once")



<template>
  <div class="q-pa-md">
    <div class="row no-wrap q-gutter-md">
      <q-btn label="Add row" color="primary" @click="addRow" :disable="listItems.length >= 7" />
      <q-btn label="Remove row" color="accent" @click="removeRow" :disable="listItems.length === 0" />
    </div>

    <div class="row no-wrap q-col-gutter-md">
      <div v-mutation="handler" class="col-4">
        <q-list v-if="listItems.length > 0" bordered separator class="q-mt-md rounded-borders">
          <q-item v-for="(item, index) in listItems" :key="item" :id="`item-${index}`">
            <q-item-section>
              {{ item }}
            </q-item-section>
          </q-item>
        </q-list>
      </div>

      <div class="col-8">
        <q-card v-if="mutationInfo.length > 0" bordered flat class="q-mt-md overflow-auto">
          <pre class="catch-all-pre q-pa-md">{{ mutationInfo }}</pre>
        </q-card>
      </div>
    </div>
  </div>
</template>

拖拽示例

下面的示例只会在桌面浏览器中生效,因为它依赖于浏览器提供的拖拽 api。将带颜色的块拖放到另外一个方框中,以查看效果。



<template>
  <div>
    <div class="row no-wrap justify-around q-px-md q-pt-md">
      <div
        v-mutation="handler1"
        @dragenter="onDragEnter"
        @dragleave="onDragLeave"
        @dragover="onDragOver"
        @drop="onDrop"
        class="drop-target rounded-borders overflow-hidden"
      >
        <div
          id="box1"
          draggable="true"
          @dragstart="onDragStart"
          class="box navy"
        />
        <div
          id="box2"
          draggable="true"
          @dragstart="onDragStart"
          class="box red"
        />
        <div
          id="box3"
          draggable="true"
          @dragstart="onDragStart"
          class="box green"
        />
        <div
          id="box4"
          draggable="true"
          @dragstart="onDragStart"
          class="box orange"
        />
        <div
          id="box5"
          draggable="true"
          @dragstart="onDragStart"
          class="box navy"
        />
        <div
          id="box6"
          draggable="true"
          @dragstart="onDragStart"
          class="box red"
        />
        <div
          id="box7"
          draggable="true"
          @dragstart="onDragStart"
          class="box green"
        />
        <div
          id="box8"
          draggable="true"
          @dragstart="onDragStart"
          class="box orange"
        />
      </div>

      <div
        v-mutation="handler2"
        @dragenter="onDragEnter"
        @dragleave="onDragLeave"
        @dragover="onDragOver"
        @drop="onDrop"
        class="drop-target rounded-borders overflow-hidden"
      />
    </div>

    <div class="row justify-around items-start">
      <div class="col row justify-center q-pa-md">
        <div class="text-subtitle1">
          Mutation Info
        </div>
        <div v-for="status in status1" :key="status">
          {{ status }}
        </div>
      </div>

      <div class="col row justify-center q-pa-md">
        <div class="text-subtitle1">
          Mutation Info
        </div>
        <div v-for="status in status2" :key="status">
          {{ status }}
        </div>
      </div>
    </div>
  </div>
</template>

Mutation Info
Mutation Info

撤销/恢复示例

v-mutation的一个经典用例是在应用中实现撤消/恢复堆栈。您可以根据自己要求监听数据的变化,并将这些变化存储在一个堆栈中,并通过这个堆栈实现撤消/恢复的功能。



<template>
  <div class="q-pa-md">
    <div class="row justify-start items-center q-mb-md">
      Max Stack Depth: {{ maxStack }}
    </div>

    <div class="row justify-around items-center">
      <div class="row items-center q-px-md q-gutter-sm">
        <q-btn label="Undo" color="primary" :disable="undoStack.length === 0" @click="undo" />
        <div>Stack Depth: {{ undoStack.length }}</div>
      </div>

      <div class="row items-center q-px-md q-gutter-sm">
        <q-btn label="Redo" color="accent" :disable="redoStack.length === 0" @click="redo" />
        <div>Stack Depth: {{ redoStack.length }}</div>
      </div>
    </div>

    <div class="row justify-around items-center q-mt-md">
      <div
        ref="editorRef"
        v-mutation="handler"
        contentEditable="true"
        class="editable rounded-borders q-pa-sm overflow-auto"
      >Type here</div>
    </div>
  </div>
</template>

Max Stack Depth: 100
Stack Depth: 0
Stack Depth: 0
Type here

视频讲解

若仍有疑惑,请观看视频讲解