Vue Devtools

Installing Vue Devtools in a browser helps you see components and values passing between groups, which is pretty handy.

Evaluate properties vs methods

When do you use computed properties and when do you use methods?

The biggest difference between computed properties and methods is that computed properties are cached based on their reactive dependencies.

That is, the calculated property is reevaluated only if the associated reactive dependency changes, and the method is invoked every time. In general, calculated properties can sometimes improve performance more than methods.

Why do we need caching? Suppose we have A computationally expensive property, A, that iterates through A large array and does A lot of computations. And then we might have other computational properties that depend on A. Without caching, we would inevitably execute A’s getter multiple times!

Evaluate properties vs listeners

Computed properties are also very similar to listeners, so when do you use computed properties and when do you use listeners? (The following are examples from the official website, which are quite easy to understand)

<div id="demo">{{ fullName }}</div>
var vm = new Vue({
  el: '#demo'.data: {
    firstName: 'Foo'.lastName: 'Bar'.fullName: 'Foo Bar'
  },
  // When using a listener
  watch: {
    firstName: function (val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})
Copy the code
// when calculating attributes
var vm = new Vue({
  el: '#demo'.data: {
    firstName: 'Foo'.lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})
Copy the code

With the above code, does it feel more appropriate to compute properties?

While computing properties is more appropriate in most cases, sometimes a custom listener is required. That’s why Vue provides a more generic way to respond to changes in data with the Watch option. This approach is most useful when asynchronous or expensive operations need to be performed when data changes.

<div id="watch-example">
  <p>
    Ask a yes/no question:
    <input v-model="question">
  </p>
  <p>{{ answer }}</p>
</div><! Because the ecosystem of AJAX libraries and common tools is already quite rich, the Vue core code is not duplicated --> <! Provide these features to keep things lean. This also gives you the freedom to choose the tools you're more familiar with. --><script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
  el: '#watch-example'.data: {
    question: ' '.answer: 'I cannot give you an answer until you ask a question! '
  },
  watch: {
    // If 'question' changes, the function is run
    question: function (newQuestion, oldQuestion) {
      this.answer = 'Waiting for you to stop typing... '
      this.debouncedGetAnswer()
    }
  },
  created: function () {
    // '_. Debounce' is a function that limits the frequency of operations through Lodash.
    // In this case, we want to limit the frequency of access to yesNo. WTF/API
    // The AJAX request is not sent until the user has entered. Want to learn more about
    // '_. Debounce' functions (and their relatives' _. Throttle '),
    // Please refer to https://lodash.com/docs#debounce
    this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)},methods: {
    getAnswer: function () {
      if (this.question.indexOf('? ') = = = -1) {
        this.answer = 'Questions usually contain a question mark. ; -) '
        return
      }
      this.answer = 'Thinking... '
      var vm = this
      axios.get('https://yesno.wtf/api')
        .then(function (response) {
          vm.answer = _.capitalize(response.data.answer)
        })
        .catch(function (error) {
          vm.answer = 'Error! Could not reach the API. ' + error
        })
    }
  }
})
</script>
Copy the code

In this example, using the Watch option allows us to perform an asynchronous operation (accessing an API), limit how often we perform that operation, and set the intermediate state until we get the final result. These are all things you can’t do with computed properties.

In general, using listeners is more appropriate when asynchronous or expensive operations need to be performed.

Evaluate the setter for the property

By default, you only have getters for computed properties, but you can also provide a setter if needed:

computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]}}}Copy the code

Manage reusable elements with keys

Vue renders elements as efficiently as possible, often reusing existing elements rather than rendering them from scratch. This has other benefits besides making Vue very fast. For example, if you allow users to switch between different login methods:

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address">
</template>
Copy the code

As in the above code, when you enter text in the input field and loginType is not username, switch the template. Since both templates use the same element, vue just replaces the placeholder value in the input. The entered text in the input field does not change.

However, this is not always practical, so Vue gives us a way to say “These two elements are completely separate, don’t reuse them”. Simply add a key attribute with a unique value:

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>
Copy the code

With the key attribute added, each change is now re-rendered, meaning that the text entered in the input box is no longer reused (the label element is still reused efficiently because no key attribute is added).

Dynamic components

Sometimes it is useful to dynamically switch between components, such as in a multi-tab interface: this can be done by adding a special IS attribute to the Component element of a Vue


<div id="dynamic-component-demo" class="demo">
      <button
        v-for="tab in tabs"
        :key="tab"
        @click="currentTab = tab">
        {{ tab }}
      </button><! -- The component will be in`currentTabComponent`Change when you change --><component v-bind:is="currentTabComponent"></component>
</div>

<script>
      Vue.component("tab-home", {
        template: "<div>Home component</div>"
      });
      Vue.component("tab-posts", {
        template: "<div>Posts component</div>"
      });
      Vue.component("tab-archive", {
        template: "<div>Archive component</div>"
      });

      new Vue({
        el: "#dynamic-component-demo".data: {
          currentTab: "Home".tabs: ["Home"."Posts"."Archive"]},computed: {
          currentTabComponent: function() {
            return "tab-" + this.currentTab.toLowerCase(); }}});</script>
Copy the code

props

Type: Array < string > | Object

Details:

Props can be arrays or objects that receive data from the parent component. Props can be a simple array, or instead, objects allow you to configure advanced options such as type checking, custom validation, and setting defaults.

You can use the following options based on the object syntax:

Type: Can be one of the following native constructors: String, Number, Boolean, Array, Object, Date, Function, Symbol, any custom constructor, or an Array of the above. Checks if a prop is of the given type, otherwise raises a warning.

Default: any

Specify a default value for this prop. If the prop is not passed in, use this value instead. The default value of an object or array must be returned from a factory function.

Required: a Boolean

Defines whether the prop is mandatory. In non-production environments, if the value is truthy and the prop is not passed in, a console warning will be thrown.

The validator: Function

The custom validation function substitutes the value of the prop as its only argument. In non-production environments, if this function returns a value of Falsy (that is, validation failure), a console warning will be thrown.

// Simple syntax
Vue.component('props-demo-simple', {
  props: ['size'.'myMessage']})// Object syntax to provide validation
Vue.component('props-demo-advanced', {
  props: {
    // Test type
    height: Number.// Test type + other validations
    age: {
      type: Number.default: 0.required: true.validator: function (value) {
        return value >= 0}}}})Copy the code

Disabling Attribute Inheritance

Let’s think about it through an example.

Parent the parent – component. Vue

<template><div class="parent">
    <child-component aaa="1111"></child-component>
  </div>
</template>
<script>
import ChildComponent from './child-component'
export default {
  components: {
    ChildComponent
  }
}
</script>
Copy the code

InheritAttrs: true (default)

<template>
  <div class="child">Child components</div>
</template>
<script>
export default {
  inheritAttrs: true.mounted() {
    console.log('this.$attrs'.this.$attrs)
  }
}
</script>
Copy the code

The final render result:

Elements

Console

Child child-component.vue sets inheritAttrs: false

<template>
  <div class="child">Child components</div>
</template>
<script>
export default {
  inheritAttrs: fasle,
  mounted() {
    console.log('this.$attrs'.this.$attrs)
  }
}
</script>
Copy the code

The final render result:

Elements

Console

Conclusion:

As you can see from the example above, the premise is that the properties passed by the parent component are not registered in the props of the child component.

When inheritAttrs is set to true (the default), attributes passed by the parent are rendered in the child’s top tag element (the div element in this example).

When inheritAttrs: false is set, the inheritAttrs element in the child component’s top tag element (the div element in this example) does not render attributes passed by the parent component (aaa=”1111″ in this example).

If inheritAttrs is true or false, a child component can use the $attrs attribute to get attributes passed in from the parent component.

This example and summary are taken from this article, which is very easy to understand:

InheritAttrs attribute for the VUE component

The sync modifier

In Vue, the most common way for parent and child components to communicate is to transfer data through props. The props value can only be updated from the parent component and transmitted to the child component. In the child component, it is not allowed to change the transmitted props value to ensure one-way data flow. But there are times when we need to change the props property value inside the child component and update it to the parent component, and we need the.sync modifier.

<text-document
  :title="doc.title"
  @update:title="doc.title = $event"
></text-document>

// Use the.sync modifier

<text-document :title.sync="doc.title">
</text-document>
Copy the code

Sync =”doc.title” is equivalent to :title=”doc.title” @update:title=”doc.title = $event”. Vue provides an abbreviation for this mode.

The native modifier

The. Native modifier is used to bind native events to a component (native converts a VUE component into a plain HTML tag) so that the root element of the component can listen for native events.

<base-input v-on:focus.native="onFocus"></base-input>
Copy the code

Use keep-alive on dynamic components

<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>
Copy the code

Keep-alive allows component instances to be cached the first time they are created. For example, the keep-alive cache allows components to remain in their original state during Posts and Archive transitions.

provide / inject

Function: Parent component transfers data to descendant component, provide parent component returns data to descendant component, Inject data in descendant component or grandchild component that needs to use this data.

// The parent component passes the value
provide: function () {
  return {
    getMap: this.getMap
  }
}

// Descendant components receive values
inject: ['getMap']
Copy the code

⚠️ Note: provide and Inject binding are not responsive. This is intentional. However, if you pass in a listening object, the object’s property is still responsive.

Render function & JSX

Render is an alternative to string templates that allows you to get the best out of JavaScript. The render function takes a createElement method as the first argument to create a VNode. If the component is a function component, the render function also receives an additional context parameter to provide context information for the function component that has no instance.

JSX is an XML-like syntax extension of JavaScript without any defined semantics, that is, JSX allows us to use HTML-like syntax in JS. Here is an example of JSX syntax combined with the render function.

new Vue({
  el: '#demo'.render: function (h) {
    return (
      <AnchoredHeading level={1}>
        <span>Hello</span> world!
      </AnchoredHeading>)}})Copy the code

⚠️ Note: using H as an alias for createElement is a general convention in the Vue ecosystem and is actually required by JSX.

The filter

Filters can be used in two places: double curly brace interpolation and V-bind expressions. Filters should be added to the end of JavaScript expressions, indicated by the “pipe” symbol:

<! - in a pair of curly braces - > {{message | filterMsg}} <! -`v-bind`-- - ><div v-bind:id="rawId | filterInfo"></div>
Copy the code

We can also define filters in the component.

filters: {
  filterMsg: function (value) {
    if(! value)return ' '
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)}}Copy the code

Filters can be connected in series:

{{ message | filterA | filterB }}
Copy the code

vm.$nextTick( [callback] )

Effect: Postponing the callback until after the next DOM update cycle. Use the data immediately after you modify it, and then wait for DOM updates. It is the same as the global method vue.nexttick, except that the this callback is automatically bound to the instance calling it.

Vue.component('example', {
  template: '<span>{{ message }}</span>'.data: function () {
    return {
      message: 'Not updated'}},methods: {
    updateMessage: function () {
      this.message = 'Updated'
      console.log(this.$el.textContent) // => 'not updated'
      this.$nextTick(function () {
        console.log(this.$el.textContent) // => 'Updated'}}}})Copy the code

Vue.compile( template )

Compiles a template string into the render function. Only available in the full version.

var res = Vue.compile('<div><span>{{ msg }}</span></div>')

new Vue({
  data: {
    msg: 'hello'
  },
  render: res.render,
  staticRenderFns: res.staticRenderFns
})
Copy the code