vue component of front-end web

Component introduction

Components are reusable Vue instances with a name.
Components can extend HTML elements to encapsulate reusable code.
Component systems allow us to build large applications with independent reusable widgets, and the interface of almost any type of application can be abstracted into a component tree.
Components are reusable vue instances, so they can also receive options such as data, computed, watch, methods, and life cycle hooks

Custom Components

The vue component is divided into global and local components.

Global Components

Use Vue. Compoonent defines the global component and then specifies a container element within each page with a new Vue ({el:'#container'}).

Use steps

Register Components

  • Call vue.extend() creates a component constructor.
    The constructor has an option object whose template property can be used to define the HTML to be rendered by the component. You can also omit the constructor and use the template property directly when grouping components.
var MyComponent = Vue.extend({
  // Options...
})
  • Use vue.component() registers components and associates constructors with components.
    Two parameters are required: the label of the component and the component constructor. vue.component() calls the component constructor internally to create a component instance.
// Register component globally, tag is my-component
Vue.component('my-component', MyComponent)

To simplify component usage, you can register a component by passing in an option object directly to the Vue instead of a constructor. Component () and component options. Vue.js automatically calls Vue behind it. Extend ().

Vue.component('component-name', {
 data: 'Component data',
 template: 'Component template content'
})

Example usage:

<meta charset="utf-8">
    <title>vue Small White</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <body>
        <div id="app">
			<button-counter></button-counter>
		</div>
        <script>			
			Vue.component('button-counter', {
			 data: function() {
			  return {
			   count: 0
			  }
			 },
			 template: '<button v-on:click="count++">Clicked{{count}}second</button>'
			})
            vm = new Vue(
                {
                    el: "#app"
                    }
            )
        </script>
    </body>
</html>

Be careful:
data must be a function and component template content must be a single followed element

Mount Components

Mount the build under a vue instance.
Once registered, the component can be used in the module of the parent instance as a custom element <my-component>.

<div id="example">
  <my-component></my-component>
</div>

Sample code:

    <meta charset="utf-8">
    <title>vue Small White</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <body>
        <div id="app">
			<btn-component></btn-component>
		</div>
        <script>
			let btn_template =  Vue.extend(
			{
				template: "<input type='button' value='vue project'> </input>"
			}
			)
			
			Vue.component('btn-component', btn_template)
            vm = new Vue(
                {
                    el: "#app"
                    }
            )
        </script>
    </body>
</html>

Global Component Usage Scenario

Global components are recommended if the specific functionality of the component needs to be used in any tags mounted by the Vue instance.

  • Global components can be used in any tag that is suspended.
  • The template genus must be included in the global component's configuration object.

Disadvantages of global components

  • Global definitions force naming not to repeat in each component
  • String templates lack syntax highlighting and use ugly\ when HTML has multiple lines
  • No CSS support means that CSS is obviously missing when HTML and JavaScript are componentized
  • No build step restricts the use of HTML and ES5 JavaScript, not preprocessors such as Pug (formerly Jade) and Babel

Local Components

Global registration is often not ideal. For example, if you use a build system like webpack, registering all components globally means that even if you no longer use a component, it will still be included in your final build. This has resulted in an unnecessary increase in JavaScript downloads by users.
In these cases, you can define components through a common JavaScript object:

var ComponentA = { /*...*/ }
var ComponentB = { /*...*/ }
var ComponentC = { /*...*/ }

new vue({
 el: '#app',
 components: {
  'component-a': ComponentA,
  'component-b': ComponentB,
  'component-c': ComponentC,
 }
})

Component Modularization

Locally registered components in modules

If a module system of webpack is used. You can create a components directory and place each component in its own file. Then, import the components before registering locally.
Suppose ComponentA is created under the components folder. Vue file, we can create a new file ComponentB. Import components in Vue as follows

import ComponentA from './ComponentA'
import ComponentC from './ComponentC'

export default {
  components: {
    ComponentA,
    ComponentC
  },
  // ...
}

Component Globalization

Maybe many of your components just wrap up elements like an input box or a button, which is relatively generic. We sometimes refer to them as basic components, and they are frequently used in various components.
As a result, many components will have a long list containing the underlying components:

import BaseButton from './BaseButton.vue'
import BaseIcon from './BaseIcon.vue'
import BaseInput from './BaseInput.vue'

export default {
  components: {
    BaseButton,
    BaseIcon,
    BaseInput
  }
}

If you use a webpack, you can use require in application entry files such as src/main.js. Context registers only these very common underlying components globally.

import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context(
  // Relative path to its component directory
  './components',
  // Whether to query its subdirectories
  false,
  // Regular expression matching the file name of the underlying component
  /Base[A-Z]\w+\.(vue|js)$/
)

requireComponent.keys().forEach(fileName => {
  // Get Component Configuration
  const componentConfig = requireComponent(fileName)

  // Gets the PascalCase naming of the component
  const componentName = upperFirst(
    camelCase(
      // Get a file name independent of directory depth
      fileName
        .split('/')
        .pop()
        .replace(/\.\w+$/, '')
    )
  )

  // Global Register Component
  Vue.component(
    componentName,
    // If this component option was exported via `export default',
    // Then it will take precedence. default`,
    // Otherwise, it falls back to the root of the module being used.
    componentConfig.default || componentConfig
  )
})

Data Interaction Between Components

Parent component passes value to child component via props

Basic Usage

Prop is some custom attribute that you can register on the component. When a value is passed to a prop attribute, it becomes an attribute of that component instance.
The subcomponent receives the passed value through props:

Vue.component('blog-post', {
// Used to receive data passed by parent components
  props: ['title'],
  template: '<h3>{{ title }}</h3>'
})

Parent components pass values to child components through attributes:

//The parent component title property passes values to the child component
<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>

Browser effects:

Dynamic transfer prop

Get a dynamic property array
In a real project, attribute values are usually obtained from the API without knowing the length of the attribute list passed in advance. In this case, v-bind can be used to dynamically transfer prop.
For property values in the parent component, you can get the corresponding property values in the data property. For the example above, you can define a data array to store attribute values corresponding to title s.

<meta charset="utf-8">
    <title>vue Small White</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <body>
        <div id="app">
			<!-- Parent Component title Property passes value to subcomponent -->
			<blog-post v-for="post in posts" v-bind:key='post.id' v-bind:title="post.title"></blog-post>
		</div>
        <script>			
			Vue.component('blog-post', {
			  props: ['title'], // Used to receive data received by parent components
			  template: '<h3>{{ title }}</h3>'
			})
            vm = new Vue(
                {
                    el: "#app",
					data: {
						posts: [
							{id: 1, title: "My journey with Vue"},
							{id: 2, title: "Blogging with Vue"},
							{id: 3, title: "Why Vue is so fun"}
						]
					}
				}
            )
        </script>
    </body>
</html>

Get Dynamic Properties
Defining props for each property becomes more complex as the properties of the component become more and more complex. For example:

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:title="post.title"
  v-bind:content="post.content"
  v-bind:publishedAt="post.publishedAt"
  v-bind:comments="post.comments"
></blog-post>

At this point, an object can be defined directly in prop, and attributes can be used automatically in template s when new attributes are added to the object

        <div id="app">
			<!-- Parent Component title Property passes value to subcomponent -->
			<blog-post v-for="post in posts" v-bind:key='post.id' v-bind:post="post"></blog-post>
		</div>
        <script>			
			Vue.component('blog-post', {
			  props: ['post'], // Used to receive data received by parent components
			  template: `
						<div class="blog-post">
						  <h3>{{ post.title }}</h3>
						  <div v-html="post.content"></div>
						</div>
					  `
			})
            vm = new Vue(
                {
                    el: "#app",
					data: {
						posts: [
							{id: 1, title: "vue", content: "Hello vue", "comment": "front-end"},
							{id: 2, title: "python", content: "Hello python", "comment": "back-end"},
							{id: 3, title: "java", content: "Hello java", "comment": "back-end"}
						]
					}
				}
            )
        </script>

Browser effects:

Change the value of prop

Each time the parent component updates, all props of the child component are updated to the latest value. This means that you should not change prop inside the subcomponent. If you do, Vue will warn you in the console.

Typically, there are two scenarios for changing prop:

  • prop is passed in as an initial value, and the subcomponent then simply uses its initial value as the initial value of the local data.
  • prop is passed in as the original value that needs to be transformed.

Scenario 1: Define a local data property and use the initial value of prop as the initial value of the local data.

props: ['initialCounter'],
data: function () {
 return { counter: this.initialCounter }
}

Scenario 2: Define a computed property that is calculated from the value of prop.

props: ['size'],
computed: {
 normalizedSize: function () {
   return this.size.trim().toLowerCase()
 }
}

prop validation

Components can specify validation requirements for props. If no validation requirements are specified, Vue will issue a warning. This is useful when components are used by others.
When prop is an object and not an array of strings, it contains validation requirements:

Vue.component('example', {
  props: {
    // Basic type detection (`null` means any type can work)
    propA: Number,
    // Multiple types
    propB: [String, Number],
    // Required and String
    propC: {
      type: String,
      required: true
    },
    // Number, with default
    propD: {
      type: Number,
      default: 100
    },
    // Default values for arrays/objects should be returned by a factory function
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // Custom Validation Functions
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }
})

Types can be the following native constructors:

  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array

Typee can also be a custom constructor that uses instanceof detection.
When prop validation fails, the Vue will refuse to set this value on the subcomponent, and a warning will be thrown if the development version is used.

Child components send messages to parent components via events

Custom events are required for subcomponents to pass data back.

Listen for subcomponent events

You can use v-on bindings to customize events, and each Vue instance implements an Events interface, which is:

  • Use $on(eventName) to listen for events.
    Vm. $ On (event, fn) //Run FN after listening for an event;
  • Use $emit(eventName) to trigger custom events for parent components.
    Vm. $ Emit (event, arg)//Trigger an event on the current instance;

Parent components can use v-on directly to listen for events triggered by child components where they are used.
The sample code is as follows:

<meta charset="utf-8">
    <title>vue Small White</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <body>
        <div id="app">
			<!-- Parent component listens for events from child components increment -->
			<p>{{ total }}</p>
			<button-counter v-on:increment="incrementTotal"></button-counter>
			<button-counter v-on:increment="incrementTotal"></button-counter>
		</div>
        <script>			
			Vue.component('button-counter', {
			  template: '<button v-on:click="incrementhandler">{{ counter }}</button>',
			  data: function () {
			      return {
			        counter: 0
			      }
			    },
				methods: {
				    incrementhandler: function () {
				      this.counter += 1
				      this.$emit('increment') //Subcomponent triggers increment event
				    }
				  }
						
			})
            vm = new Vue(
                {
                    el: "#app",
					data: {
					    total: 0
					  },
					  methods: {
					    incrementTotal: function () {
					      this.total += 1
					    }
					  }
				}
            )
        </script>
    </body>
</html>

Browser effects:

Event throw value

The second parameter of $emit passes data to the parent component
Data passed by child components can be captured in parent component by $event

<meta charset="utf-8">
    <title>vue Small White</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <body>
        <div id="app">
          <div :style="{ fontSize: postFontSize + 'em' }">
            <blog-post
              v-for="post in posts"
              v-bind:key="post.id"
			  <!-- From the parent component, the $event Capture data passed by subcomponents -->
              v-bind:post="post" v-on:enlarge-text="postFontSize += $event"
            ></blog-post>
          </div>
        </div>
        <script>			
			Vue.component('blog-post', {
			  props: ['post'],
			  template: `
			    <div class="blog-post">
			      <h3>{{ post.title }}</h3>
				  // The second parameter of $emit passes data to the parent component
			      <button v-on:click="$emit('enlarge-text', 0.1)">
			        Enlarge text
			      </button>
			      <div v-html="post.content"></div>
			    </div>
			  `
			})
            vm = new Vue(
                {
                    el: '#app',
					data: {
                        posts: [
							{id: 1, content: "hello", title: "btn_1"},
							{id: 2, content: "hello vue", title: "btn_2"}
							],
                        postFontSize: 1
                     }
				}
            )
        </script>
    </body>
</html>

In a real project, a parent component can define a function that receives a child component event value.

<meta charset="utf-8">
    <title>vue Small White</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <body>
        <div id="app">
          <div :style="{ fontSize: postFontSize + 'em' }">
            <blog-post
              v-for="post in posts"
              v-bind:key="post.id"
              v-bind:post="post" v-on:enlarge-text="enlargeText"
            ></blog-post>
          </div>
        </div>
        <script>			
			Vue.component('blog-post', {
			  props: ['post'],
			  template: `
			    <div class="blog-post">
			      <h3>{{ post.title }}</h3>
			      <button v-on:click="$emit('enlarge-text', 0.1)">
			        Enlarge text
			      </button>
			      <div v-html="post.content"></div>
			    </div>
			  `
			})
            vm = new Vue(
                {
                    el: '#app',
					data: {
                        posts: [
							{id: 1, content: "hello", title: "btn_1"},
							{id: 2, content: "hello vue", title: "btn_2"}
							],
                        postFontSize: 1
                     },
					 methods:{
					 					  enlargeText: function (cnt) {
					 					  this.postFontSize += cnt
					 				  }
					 }
				}
            )
        </script>
    </body>
</html>

v-model data bidirectional binding

Custom events are used to create custom form input components that can use v-model for data bidirectional binding.
The essence of the v-model directive is that it listens for user input events, updates data, and performs some special handling of extreme scenarios. At the same time, the v-model ignores the initial values of the value, checked, selected attributes of all form elements, and always uses the data from the vue instance as the data source. Then, when the input event occurs, the data in the vue instance is updated in real time.

<input v-model="something">
//value automatically assigns input values to the attr field of the vue instance.

Just a grammatical sugar, equivalent to:

<input v-bind:value="something" v-on:input="something = $event.target.value">

When used in a component, it corresponds to the following abbreviation:

<custom-input v-bind:value="something" v-on:input="something = arguments[0]"></custom-input>

The v-model of the component is valid and must:

  • Accept a value attribute
  • Trigger the input event when a new value exists

Example:
The input box receives price, and when v-model is not used, the code is as follows

<meta charset="utf-8">
    <title>vue Small White</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <body>
        <div id="app">
			<price-input :value="price" @input="onInput"></price-input>
			<p>Input price: {{price}}</p>
          </div>
        <script>			
			Vue.component('price-input', {
			  props: ['value'],
			  template: `
					<div>
					<input
					  type="text"
					  placeholder="Please enter"  
					  v-bind:value="value"
					  v-on:input="updateVal($event.target.value)"
					>
					</div>
			  `,
			  methods: {
				  updateVal: function(val) {
					  this.$emit('input', val);  
				  }
			  }
			})
            vm = new Vue(
                {
                    el: '#app',
					data:{
						price:'123'
						},
					methods: {
							  onInput: function (val) {
								console.log("Console Printing output details")
								this.price = val
								console.log(this.price)
							  }  
					}
				}
				
            )
        </script>
    </body>
</html>

Replace the complex two-way binding process with v-model, coded as follows

<meta charset="utf-8">
    <title>vue Small White</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <body>
        <div id="app">
			<price-input v-model="price"></price-input>
			<p>Input price: {{price}} </p>
          </div>
        <script>			
			Vue.component('price-input', {
			  props: ['value'],
			  template: `
					<div>
					<input
					  type="text"
					  placeholder="Please enter"  
					  v-bind:value="value"
					  v-on:input="updateVal($event.target.value)"
					>
					</div>
			  `,
			  methods: {
				  updateVal: function(val) {
					  this.$emit('input', val);  
				  }
			  }
			})
            vm = new Vue(
                {
                    el: '#app',
					data:{
						price:'123'
						},
					methods: {
							  onInput: function(val) {
								this.price = val
								console.log("Console Printing output details: " + this.price)
							  }  
					}
				}
            )
        </script>
    </body>
</html>

Reference:
Official vue document

Tags: Front-end Vue

Posted by macattack on Sat, 21 May 2022 20:25:38 +0300