In the daily project development process, it is often inseparable from the process of packaging components. For example, page A has a function that happens to be used by page B and page C. At this point we consider making this feature a component for code reuse. In this article, we will talk about some tips and techniques for developing vUE components.

We’re going to go through a lot of examples

All the sample code for this article has been uploaded to Github


directory

  • General feature component tips
  • Functional component
  • Inline template
  • Recursive components
  • v-onceLow overhead static components
  • Global function calls components

General feature component tips

First we scaffolding a project to write our components. The UI framework we use is Iview. The writing of functional components is inseparable from the communication between components. There are many related articles, which will not be elaborated in detail in this article. Here, I recommend a golden article about component communication.

Slot slot

Slot slots should have a high presence when we normally write components. Using the

element as an outlet to host the distribution, we can include any template code in the slot, which makes our components more flexible. Let’s look at a classic example of a dialog box component, starting with the code.

<template> <div> <div> <slot> Default content </slot> </div> <div> <slot name="footer"> <Button> Confirm </Button> </slot> </div> </div> </template> <script> export default { name: "model" }; </script>Copy the code

All code in the Model tag, except for code with slot as footer, will be displayed as the body of the dialog box, which is how the scope slot is used. The code for slot as footer will be displayed in the bottom action button section, corresponding to

that’s how named slots are used.

Attribute passthrough

There are few scenarios in which attribute pass-through occurs. Let’s take the secondary encapsulation of UI components as an example. If you use a UI component frequently in your project, and the UI component sets a lot of similar properties each time, then you can rewrap it, make it easier to call, and even extend the functionality on the original component. Let’s look at a piece of code that rewraps the Table component of Iview.

<script>
import { Table } from "iview";
export default {
  name: "customizeTable".props: { ...Table.props, test: { type: [String].default: "Extended properties" } },
  data() {
    return { defaultProps: { border: true.stripe: true}}; }, render(h) {var props = Object.assign({ ... this._props },this.defaultProps);
    return h(Table, { props: props }); }};</script>Copy the code

/ / method 2

<template> <div> <Table v-bind="{... mergeProps}"></Table> </div> </template> <script> import { Table } from "iview"; export default { name: "customizeTable", props: { ... Table. Props, test: {type: [String], default: "Extended properties"}}, computed: {mergeProps: function() { return Object.assign({ ... this._props }, this.defaultProps); } }, data() { return { defaultProps: { border: true, stripe: true } }; }}; </script>Copy the code

We can get all the default parameters of the Table using the props property of the Table component. Then we can pass through the properties of this._props. In method one, we bind properties using the Render method, which we’ll discuss in more detail in functional components. In method two, we use V-bind to bind all the attributes in the object.



Functional component

Let’s take a look at functional components from the official website

A functional component that does not manage any state, does not listen for any state passed to it, and has no lifecycle methods. Really, it’s just a function that accepts some prop. In such a scenario, we can mark the component as functional, which means it is stateless (no responsive data) and has no instance (no this context).

Everything a component needs is passed through the context parameter, which is an object containing the following fields:

  • props: Provides objects for all prop
  • children: An array of VNode children
  • slots: a function that returns an object containing all slots
  • scopedSlots: (2.6.0+) An object that exposes the incoming scope slot. Normal slots are also exposed as functions.
  • data: passes to the entire componentThe data objectAs acreateElementThe second parameter is passed to the component
  • parent: a reference to the parent component
  • listeners: (2.3.0+) An object that contains all event listeners registered by the parent component for the current component. This is adata.onAn alias for “.
  • injections: (2.3.0+) If usedinjectOption, the object contains properties that should be injected.

Adding functional: After true, we need to update our anchor title component’s render function to add context and update this.$slot.default to context.children, Then update this.level to context.props. Level.

Why use functional components?

Since functional components have no life cycle, stateless, and no instances, that means they render faster and cheaper, and because functional components are just functions, we can implement some of the logic we need in functions.

When to use functional components?

In my opinion, functional components are more of a middleware role, so their more common application scenario is as a wrapper component. For example, if we have a component that may render one of several components, depending on the parameters passed, we need to decide which component to render. Let’s look at a piece of code.

export default { 
  functional: true.render: function (createElement, context) { 
    returncreateElement(context.props.domType, context.data, context.children); }}Copy the code

<template> <div> <functionnalScript domType="model" style="width:100%"></functionnalScript> </div> </template> <script> import customizeTable from ".. /components/customizeTable.vue"; import model from ".. /components/model.vue"; import functionnalScript from ".. /components/functionnal.js"; export default { name: "pageA", components: { customizeTable, model, functionnalScript: functionnalScript } }; </script>Copy the code
// The template’s functional component function.vue

<template functional>
  <div>
    <button v-bind="data.attrs" v-on="listeners">
      <slot />
    </button>
  </div>
</template>Copy the code

Normally when we call the parent page we have the customizeTable component and the Model component and we can display the corresponding component by specifying functionnalScript in a property called domType, and it can be reused in multiple places.

The functional component of a template allows you to fully pass through any attribute, event listener, child node, and so on.

Inline template

A component’s template is defined in the template option. When using a component, an inline template uses the inline-template feature for the component’s tag. The component treats its content as a template rather than distributing it as content, making the template more flexible. But this leads to some problems, so let’s look at the code.

<script>
export default {
  name: "inlineChildren",
  data() {
    return { tip: "I am the data of the child component."}; }};</script>
Copy the code

<template>
  <div>
    <inlineChildren inline-template>
      <div>
        <h3>{{tip}}</h3>
      </div>
    </inlineChildren>
  </div>
</template>
<script>
import inlineChildren from ".. /components/inlineChildren.vue";
export default {
  name: "pageA",
  components: { inlineChildren },
  data() {
    return { tip: "I'm the parent component's data."}; }}; </script>Copy the code

The presence of inline-template makes the contents of the inlineChildren tag not slot but the template of the inlineChildren component, and the context in which this part of content resides is that of the child component, not the parent component. So unless it’s a special case (which I haven’t encountered), inline-template makes the scope of a template even more difficult to understand, as stated on the official website. As a best practice, use the template option within the component or a

Recursive components

What is a recursive component?

Calling itself in the component’s own template is what we call a recursive component. (Note that it needs to be called by the component’s name)

What are the usage scenarios?

There is a lot of room for recursive components in our daily development, such as menus, comments and other hierarchical functions. Let’s look at an example of a menu:

<template>
  <div>
    <div v-for="item in menuList">
      <div class="hasChildren">{{item.name}}
        <Icon v-if="item.children" type="ios-arrow-down" />
      </div>
      <side-menu v-if="item.children" :menuList="item.children"></side-menu>
    </div>
  </div>
</template>

<script>
export default {
  name: "SideMenu",
  props: {
    menuList: {
      type: Array,
      default() {
        return[]; }}}}; </script> <style> .hasChildren { background:# 999;
  color: #fff;
  height: 40px;
  line-height: 40px;
}
</style>Copy the code

<template>
  <div>
    <sideMenu :menuList="menuList"></sideMenu>
  </div>
</template>
<script>
import sideMenu from ".. /components//side-menu.vue";
export default {
  name: "pageA",
  components: { sideMenu },
  data() {
    return {
      menuList: [
        { name: "side1", children: [{ name: "side1-1" }, { name: "side1-2" }] },
        {
          name: "side2",
          children: [
            { name: "side2-1" },
            { name: "side2-2", children: [{ name: "side2-2-1"}]}]}; }}; </script>Copy the code

We can see that the sideMenu component calls itself inside, which is the basic use of recursive components. In A more complicated case, there are two components, A and B, that call each other. There comes the question of which came first, the chicken or the egg.



The modular system finds that it needs A, but first A depends on B, but B depends on A, but A depends on B, and so on. This becomes a loop where you don’t know how to fully resolve one component without going through the other, and there are two solutions.

// Return the forecreate value for each key on the forecreate TAB.function () {
  this.$options.components.TreeFolderContents = require('./B.vue'{B: () => import()'./B.vue')}Copy the code

V-once low-overhead static component

If you have a lot of static content in your component that may cause your component to render slowly, you can add v-once attributes to the root element to ensure that the content is evaluated only once and cached.

<template>
  <div v-once> {{hugeData}} </div>
</template>

<script>
export default {
  name: "vOnce".data() {
    return { hugeData: "huge Data..." };
  },
  mounted() {
    setTimeout(() => {
      this.hugeData = "change Data..."; }, 100); }}; </script>Copy the code

You’ll find hugeData has always been Huge Data… No change, because v-once causes the data of this template to change after rendering and cannot be updated normally, so considering that other developers are not necessarily familiar with this attribute, try not to use it unless it is particularly necessary.

Global function calls components

The normal process of a component call:

<testModule></testModule>
import TestModule from "./TestModule "

export default {  components: { testModule  }};Copy the code

If you need to use this component in multiple places, which means you need to repeat the steps above every time you call it, is there a more convenient way to call it? Console. log and alert are familiar, and sometimes we want to be able to call a component this way without writing the component to the node. For example, a tip box component might need to be woken up at various times and prompted for the corresponding content. We implement this tip component in code.

//extend.js
import Vue from 'vue'import Tip from './tip.vue'; // Using the basic Vue constructor, create a "subclass" tip.newinstance = (props) => {const tip = vue.extend (tip); // Use the basic Vue constructor to create a tip.newinstance = (props) => {const tip = vue.extend (tip); const messageInstance = new tip({ propsData: props }); const div = document.createElement('div'); 
  document.body.appendChild(div); messageInstance.$mount(div) 
}
export default Tip.newInstanceCopy the code

//main.js
import tip from 'extend.js'Vue.prototype.$tip=tip; / / call this.$tip({});Copy the code

So we can call the tip component by calling this.$tip({}). As you can see, the core idea is to create a Vue instance that contains the components we need, and then mount that instance onto a newly created div. If we call this function multiple times, the page will be appended with multiple divs, which is not what we want, so we can optimize it a little bit.

<template> <div> <div v-for="item in tips"> <tip v-bind="item"></tip> </div> </div> </template> <script> let i = 0; const now = new Date().getTime(); function getUid() { return "tip" + now + "-" + i++; } import tip from "./tip.vue"; export default { name: "tipList", data() { return { tips: [] }; }, components: { tip }, methods: { add(options) { let name = getUid; let _options = Object.assign({ name: name }, options); this.tips.push(_options); }}}; </script>Copy the code

import Vue from 'vue'import Tip from './tipList.vue';
let tip, initialization;
// Using the base Vue constructor, create a "subclass" containing the TIP component
Tip.newInstance = (a)= > {  
  tip = Vue.extend(Tip);  
  const messageInstance = new tip();  
  const div = document.createElement('div'); 
  document.body.appendChild(div); 
  messageInstance.$mount(div)      
  return {          
    prompt(props) {              
      messageInstance.add(props);          
    }      
  }
}
initialization=function(){   
  if(! tip){ tip=Tip.newInstance() }return tip
}
export default initialization
//main.js
import tip from 'extend.js'
Vue.prototype.$tip=tip;
/ / call
this.$tip.prompt({});Copy the code

We use the prompt method of a component called Tiplist. vue to implement the requirement for tip components to be called multiple times. Each tip component call is equivalent to pushing an object into the TIPS array so that one more TIP component is rendered.

conclusion

Hopefully, once you’ve seen them, you’ll be able to use them in your components as well, so that your components will have less unnecessary logic. The author may have some wrong understanding, and I hope you can mention it in the comments. We can learn and make progress together.

Other article portals:

  1. Realization of web terminal large data volume table based on VUE

  2. Baidu Map – real-time update of large data volume points