Vue3.0 _ scaffolding

The official website provides two build methods, one is vite, the other is VUE-CLI. This article uses the former Vite, mainly because it is faster to build. We execute the commands in turn:

npm init vite vue3-demo 
cd vue3-demo
npm install
npm run dev
Copy the code

Vite +vue3: localhost:3000

Vue3.0 _ new features

First, the composite API(API) Composition

The purpose of a composite API is to group together code for the same logical concern, which enhances the legibility and maintainability of components without constantly jumping to and from blocks of options for related code while working on a single logical concern.

# setupoptions

  • Vue3 willsetupAs an entry point to the composite API, executed before component creation
  • setupThe option is a function that takes two parameters, props and context
  • Everything it returns can be used for the rest of the component (lifecycle, computed properties, methods, and so on) as well as the template of the component

The setup structure looks like this:

export default { components: { }, props: { user: { type: String, required: true } }, setup(props) { console.log(props) // { user: } // exposes template Return {} // whatever is returned here can be used for the rest of the component} // the "rest" of the component}Copy the code

# reffunction

  • refCreate a reactive reference to our value and return one{value: xxx}The value of a reactive variable can be accessed or changed through the value property of the object
  • It is used in conjunction with the composite API
  • fromsetupThe returned ref is automatically shallow unpacked when accessed in the template and does not need to be used in the template.value
<template>
  <div>{{ counter }}</div>
</template>
import { ref } from 'vue'
setup(){
    const counter = ref(0)
    console.log(counter) // { value: 0 }
    console.log(counter.value) // 0
    counter.value++
    console.log(counter.value) // 1 
    return {
      counter
    }
}
Copy the code

# reactivefunction

  • Take an object, return a reactive copy of the object, and make a “deep” reactive transformation of the object
  • You can unpack all the deep onesrefsWhile maintaining the responsiveness of ref
Const count = ref(1) const obj = reactive({count}) console.log(obj.count === count.value) // true // it updates 'obj.count' count.value++ console.log(count.value) // 2 console.log(obj.count) // 2 // It also updates' count 'ref obj.count++ console.log(obj.count) // 3 console.log(count.value) // 3Copy the code

# toRefsfunction

ToRefs can get a responsive reference to a prop in the props parameter of the setup option

import { watch, ToRefs} from 'vue' setup (props) {// Create a responsive reference to prop's 'user' property using 'toRefs' const {counter} = toRefs(props) watch(counter, (newValue, oldValue) => { console.log('The new counter value is: ' + counter.value) }) ... return { ... }}Copy the code

# addonPrefix life cycle function

  • Life cycles are nothing new, however with VUe3 we can write life cycle hooks in the setup option by prefixing them with on, for examplemountedinsetupIn a writtenonMounted
  • addonThe prefix’s lifecycle functions each accept a callback that is executed when the hook is called by the component
import { ref, onMounted } from 'vue' setup (props) { const repositories = ref([]) const getUserRepositories = async () => { Repositories. value = await fetchUserRepositories(props. User)} onMounted(Repositories.getUserRepositories) // `getUserRepositories` return { repositories, getUserRepositories } }Copy the code

# watchReactive changes to a function

The watch function exported from vue can take three arguments:

  • A reactive reference or getter that you want to listen for
  • A callback
  • Optional configuration options
Import {ref, watch} from 'vue' const counter = ref(0) // Watch (counter, (newValue,) oldValue) => { console.log('The new counter value is: ' + counter.value) })Copy the code

When counter is modified, such as counte.value=5, listening triggers and executes the callback (the second argument). This is equivalent to the following code:

export default {
  data() {
    return {
      counter: 0
    }
  },
  watch: {
    counter(newValue, oldValue) {
      console.log('The new counter value is: ' + this.counter)
    }
  }
}
Copy the code

# watchEffectfunction

  • Reactive trace dependencies
  • Automatic application and reapplication of secondary applications
    • Automatic application: Execute a function passed in immediately
    • Reapply side application: Rerun this function when dependent changes occur
  • Automatically stops listening when a component is uninstalled
  • Side effects are performed before component updates
  • onInvalidateThe function is used to remove side applications
  • flushOption to re-execute side applications after component updates

# independentcomputedattribute

Computed output is a responsive reference

  • Returns an immutable responserefobject
const count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 plusOne.value++ // errorCopy the code
  • Used to create writablerefobject
const count = ref(1)
const plusOne = computed({
  get: () => count.value + 1,
  set: val => {
    count.value = val - 1
  }
})

plusOne.value = 1
console.log(count.value) // 0
Copy the code

# summary

The composite API can be summarized as follows: The logic in each logical concern (that is, a separate functional module) is extracted into a separate combinative function, each of which is composed of functions derived from vUE (REF, toRefs, Watch, computed, etc.), which are introduced into the component like building blocks. We can then gather all the contents (properties, methods, etc.) of these individual function modules in the component setup function and expose them to the rest of the component (lifecycle, computed properties, methods, etc.) and the template of the component in an API-like manner.

Second, the Teleport

Teleport literally means teleportation (objects, people); Remote, so it’s not hard to guess that it acts like slot, transferring/mounting/injecting components in templates

  • There are two parameterstoanddisabled
  • It works by means oftoProperty mounts A component to A location in B that needs to be rendered, while A component’s logic is independent of B, keeping A component independent
<body> <div style="position: relative;" > <h3>Tooltips with Vue 3 Teleport</h3> <div> <modal-button></modal-button> </div> </div> </body>Copy the code
const app = Vue.createApp({});

app.component('modal-button', {
  template: `
    <button @click="modalOpen = true">
        Open full screen modal!
    </button>

    <div v-if="modalOpen" class="modal">
      <div>
        I'm a modal! 
        <button @click="modalOpen = false">
          Close
        </button>
      </div>
    </div>
  `,
  data() {
    return { 
      modalOpen: false
    }
  }
})
Copy the code

As can be seen from the above example, Teleport is used to bind the button in the frame component to the trigger logic of the frame in one component. All you need to do is to specify the place to be mounted to, that is, the body of the target element. The target element can also be an ID or class query selector. Modal-button components can be rendered normally in the template, which is logically or structurally clean.

Segments of three,

Vue3 supports multiple root nodes within a component, which means that you don’t need to wrap a DOM tag under the template tag within the component

<! -- demo.vue --> <template> <header>... </header> <main v-bind="$attrs">... </main> <footer>... </footer> </templateCopy the code

Four,emitsoptions

In component eventsemits

1. The emits option defines the events that a component can fire to its parent

<template> <div> <p>{{ text }}</p> <button v-on:click="$emit('accepted')">OK</button> </div> </template> <script> export  default { props: ['text'], emits: ['accepted'] } </script>Copy the code

2. Any event listeners not declared in emits are counted as native events in the component’s $attr and are bound by default to the component’s root node’s native event listener

<my-button V-on :click="handleClick"></my-button>Copy the code
</button V-on :click="$emit('click', $event)">OK</button> </template> <script> export default {emits: [] // do not declare events} </script>Copy the code

If the click event is not declared in the emits option, the event will be emitted twice:

  • Once from the child component$emit
  • A native event listener from the root element

3. The emits option can accept an array or object that allows event validation to be configured (the validation function should return a Boolean value).

App.component ('custom-form', {emits: {// no validation click: null, // validate the event submit: ({ email, password }) => { if (email && password) { return true } else { console.warn('Invalid submit event payload! ') return false } } }, methods: { submitForm(email, password) { this.$emit('submit', { email, password }) } } })Copy the code

Five,v-modelThe new usage

  • v-modelParameter changes:
    • vue2In: on the componentv-modelusevalueAs the prop andinputAs the event
    <ChildComponent v-model="pageTitle" /> <! <ChildComponent :value="pageTitle" @input="pageTitle = $event" />Copy the code
    • vue3In: on the componentv-modelusemodelValueAs the prop andupdate:modelValueAs the event
    <ChildComponent v-model="pageTitle" /> <! <ChildComponent :modelValue="pageTitle" @update:modelValue="pageTitle =" />Copy the code
  • Multiple V-Model bindings can be used on the same component
<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />
Copy the code
  • You can customizev-modelThe modifier
    • Vue3 used inmodelModifiersObjects are custom modifiers, that isv-modelThe modifier will passmodelModifiersProp provides components
    • When the component’screatedWhen the lifecycle hook fires,modelModifiersProp will containcapitalizeAnd its value istrue

Here’s an example of capitalizing a string whenever an input event is triggered by the element:

// html
<div id="app">
  <my-component v-model.capitalize="myText"></my-component>
  {{ myText }}
</div>
Copy the code
// vue
const app = Vue.createApp({
  data() {
    return {
      myText: ''
    }
  }
})

app.component('my-component', {
  props: {
    modelValue: String,
    modelModifiers: {
      default: () => ({})
    }
  },
  emits: ['update:modelValue'],
  created() {
    console.log(this.modelModifiers) // { capitalize: true }
  },
  methods: {
    emitValue(e) {
      let value = e.target.value
      if (this.modelModifiers.capitalize) { // true
        value = value.charAt(0).toUpperCase() + value.slice(1)
      }
      this.$emit('update:modelValue', value)
    }
  },
  template: `<input
    type="text"
    :value="modelValue"
    @input="emitValue">`
})

app.mount('#app')
Copy the code