Vue3

字数 1091 · 2021-01-18

SFC

Any top-level bindings (including variables, function declarations, and imports) declared inside <script setup> are directly usable in the template:

1
2
3
4
5
6
7
8
9
10
11
<template>
  <div @click="log"></div>
</template>
<script setup>
const msg = 'Hello!'

// functions
function log() {
  console.log(msg)
}
</script>

defineProps and defineEmits

defineProps and defineEmits are compiler macros

1
2
3
4
5
6
7
8
<script setup>
const props = defineProps({
  foo: String
})

const emit = defineEmits(['change', 'delete'])
// setup code
</script>

ES Lint Config:

1
2
3
4
5
6
7
8
9
module.exports = {
  // ...
  globals: {
    defineProps: "readonly",
    defineEmits: "readonly",
    defineExpose: "readonly",
    withDefaults: "readonly"
  }
}

Teleport

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<button @click="modalOpen = true">
    Open full screen modal! (With teleport!)
</button>

<teleport to="body">
  <div v-if="modalOpen" class="modal">
    <div>
      I'm a teleported modal! 
      (My parent is "body")
      <button @click="modalOpen = false">
        Close
      </button>
    </div>
  </div>
</teleport>
1
2
3
4
5
6
// 传送至 body
import { createVNode, h, render, Teleport } from 'vue';
render(
  createVNode(h(Teleport, { to: 'body' }, ['hello'])),
  document.createDocumentFragment() as any
);

Functional

1
2
3
function MyComponent(props, context) {
  // ...
}

Reactivity

  • targetMap - WeakMap
    • key: Reactive Object
    • value: depMap
      • key: propName
      • value
        • dep - Set of effects
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function reactive(target) {
  const handler = {
    get(target, key, receiver) {
      let result = Reflect.get(target, key, receiver);
      // track
      return result;
    },
    set(target, key, value, receiver) { // receiver ensures the proper value of `this`
      let oldValue = target[key];
      let result = Reflect.set(target, key, value, receiver);
      if (result && oldValue != value) {
        // trigger
      }
    }
    return new Proxy(target, handler);
  }
}

reactive()

The reactive conversion is “deep”: it affects all nested properties.

A reactive object also deeply unwraps any properties that are refs while maintaining reactivity.

1
2
3
4
// !! no ref unwrapping performed, also native collection type like `Map`.
const reactiveA = reactive([ref(1), ref(2)]);
 
console.log(reactiveA[0].value) // 1

Lifecycle

graph TD
  PBM --> CBM
  CM --> PM

  subgraph Child
  CBM(onBeforeMount)-->CM(onMounted)
  end

  subgraph Parent
  PBM(onBeforeMount)
  PM(onMounted)
  end

Debug

1
2
3
$vm0.setupState

$vm0.setupContext

Pinia

store is an object wrapped with reactive, can’t destructure!

1
2
3
import { storeToRefs } from 'pinia'

const { name, doubleCount } = storeToRefs(useCounterStore());
  • state
  • getters
  • actions

VueUse

Collection of Vue Composition Utilities

https://vueuse.org

Most of the functions in VueUse returns an object of refs that you can use ES6’s object destructure syntax to take what you need.

1
2
// "x" and "y" are refs
const { x, y } = useMouse()

If you prefer to use them as object properties style, you can unwrap the refs by using reactive().

1
2
3
4
const mouse = reactive(useMouse())

// "x" and "y" will be auto unwrapped, no `.value` needed
console.log(mouse.x)

useMemoize