Single file component
Single file component means that one file corresponds to one component. The name of single file component is usually xxx.vue (the naming convention is the same as that of component name)
. This file is only specified by the Vue framework. It can recognize that the browser cannot directly open and run
- The Vue framework can compile
xxx.vue files
intohtml js css
code that the browser can recognize
The content of xxx.vue file
includes three categories: structural HTML code (template tag), interactive JS code (script tag), and style CSS code (style)
- VSCode tool plug-in:
vetur
has a highlighted code when writing the xxx.vue file, and you can also generate code by entering, Auto Rename Tag
Plug-in facilitates modifying tag names at the same time
export and import
export
is used to expose data (properties, methods and objects): Common exposure methods include respective exposure, unified exposure, and default exposure
// Use the m1.js file to expose properties and methods separately export let school = 'Silicon Valley'; export function teach() { console.log("We can teach you development skills"); } // The way objects are used in the m2.js file is uniformly exposed let school = 'Silicon Valley'; function findJob(){ console.log("We can help you find a job!!"); } export {school, findJob}; // Use default exposure in m3.js file (can expose any type, usually an object) export default { school: 'ATGUIGU', change: function(){ console.log("We can change you!!"); } }
import
is used to import data (properties, methods, objects) exposed in js files
<body> <script type="module"> // Common import method, m1, m2, m3 store exposed data respectively import * as m1 from "./src/js/m1.js"; import * as m2 from "./src/js/m2.js"; import * as m3 from "./src/js/m3.js"; // The destructuring assignment form uses exposed data in the form of objects. When the attribute method has the same name, use the as keyword. // import {a, b} from 'module identifier' import {<!-- -->school, teach} from "./src/js/m1.js"; import {<!-- -->school as guigu, findJob} from "./src/js/m2.js"; // default is a keyword and cannot be used directly, you need to use the alias mechanism import {<!-- -->default as m3} from "./src/js/m3.js"; // A simple form of import but only for default exposure. m3 is an alias that stores exposed data and methods. // import any name from module identifier’ import m3 from "./src/js/m3.js"; // Accessing exposed properties and methods requires adding a default structure console.log(m3.default.school); </script> </body>
Write the introduction of all modules into a separate js file
, use the script tag in
directly Just import this js fileindex, html
, and the type is module
//Entry file introduced by the module import * as m1 from "./m1.js"; import * as m2 from "./m2.js"; import * as m3 from "./m3.js";
<body> <!--Introduce js files, the type is module--> <script src="./src/js/app.js" type="module"></script> </body>
Single file component with nested components
Component development process: The browser does not recognize the .vue file
and does not recognize the modular syntax of ES6, so it needs to install Vue scaffolding
Step 1: Create the xxx.vue
file to create components that can be nested to use other components
<!--App.vue--> <template> <div> <h1>App component</h1> <!-- Using components --> <X></X> <Y></Y> </div> </template> <script> import X from './X.vue' import Y from './Y.vue' // Expose the component export default { //Register component components : {X, Y} } </script> <!--X.vue--> <template> <div> <h2>X component</h2> <!-- Using components --> <X1></X1> </div> </template> <script> import X1 from './X1.vue' export default { //Register component components : {X1} } </script> <!--X1.vue--> <template> <div> <h3>X1 component</h3> </div> </template> <script> export default { // Expose X1 component } </script> <!--Y.vue--> <template> <div> <h2>Y component</h2> <!-- Using components --> <Y1></Y1> </div> </template> <script> //Import component Y1 (Y1 can use other names) import Y1 from './Y1.vue' export default { //Register component components : {Y1} } </script> <!--Y1.vue--> <template> <div> <h3>Y1 component</h3> </div> </template> <script> export default { //Expose Y1 component } </script>
Step 2: Use js code
to import the root component App.vue
file, create a vm instance and register the App component, and finally write this code to a main.js entry file
can be found
import App from './App.vue' new Vue({<!-- --> el : '#root', // use components template : `<App></App>`, //Register App component components : {<!-- -->App} })
Step 3: Introduce the vue.js
file and the main.js
file, and create a vm instance in the index.html
file to mount elements to contain
Step 4: Open the index.html
page. After the browser loads the vue.js and main.js files, it will create a Vue instance vm and complete the creation and registration of all components and their sub-components. Finally compile the template statement and render the page
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Single file component</title> </head> <body> <div id="root"></div> <script src="../js/vue.js"></script> <script src="./main.js"></script> </body> </html>
Develop using scaffolding components
Install Vue CLI (scaffolding)
Vue's scaffolding (Command Line Interface) is a standardized development platform officially provided by Vue to facilitate developers. Vue CLI 4.x
requires Node.js v8.9 and above (v10 is recommended above)
Step 1: Execute the npm install -g @vue/cli
command to install the scaffolding. -g
means global installation, which means you only need to install it once. Use vue
Command to test whether the installation is successful
Step 2: Execute the vue creat vue_pro
command in the specified directory, which means creating a vue_pro project (built-in Hello Word case), with its own scaffolding environment and built-in webpack loader
Step 3: Execute the npm run serve
command in the root directory of the vue_pro project to compile the Vue program. At this time, the xxx.vue
file in the project will be automatically transferred. into html css js
code
Understand the scaffolding project structure
index.html file
There is only one container in the index.html
file in the scaffolding project, and the vue.js file and the main.js file are not introduced, because the Vue scaffolding will automatically find the main.js file, prerequisite Is the file name and location fixed
<!DOCTYPE html> <html lang=""> <head> <meta charset="utf-8"> <!--Let IE browser enable the highest rendering standard, IE8 does not support Vue--> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <!-- Turn on the mobile virtual window (ideal viewport), you can set the width, height and initialization ratio of the virtual window to achieve the effect of zooming and moving when browsing the web on the mobile phone --> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <!--Set the tab icon. BASE_URL is the absolute path set by Vue to imitate Jsp syntax. Absolute paths are more stable than relative paths--> <link rel="icon" href="<%= BASE_URL %>favicon.ico"> <!--webpack will look for name in package.json as the title, or you can set it manually --> <title><%= htmlWebpackPlugin.options.title %></title> <title>Welcome to this system</title> </head> <body> <!--When the browser does not support JS language, the following prompt message is displayed--> <noscript> <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <!-- Container --> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>
Configuration file vue.config.js
The vue.config.js
file is the default configuration file of the scaffolding. For specific configuration items, please refer to the Vue CLI
official website manual
const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ transpileDependencies: true, //Whether to perform syntax checking when saving (for example, the name of the component should be composed of multiple words), the default value true means checking, false means not checking lintOnSave : false, //Configure the location and name of the entry file pages: { index: { entry: 'src/main.js', } },
Entry file main.js
Vue consists of two parts: one is the core of Vue
, and the other is the template compiler (accounting for one-third of the entire vue.js file size)
- Since the code must have been compiled when finally using webpack for packaging, the template compiler in Vue is no longer necessary at this time, so in order to reduce the size, a
missing template compiler is directly introduced by default in the Vue scaffolding. The vue.js file is the runtime-only version of Vue
Since Vue introduces the vue.js file that lacks the template compiler, the template configuration item cannot be compiled in the main.js file
when creating a Vue instance template statements, but the template statements in the template tag
of the xxx.Vue file
can be compiled normally because Vue is configured in the package.json file
- The first way: introduce a complete vue.js,
import Vue from 'vue/dist/vue.js'
- The second way: Use the
render function
instead of the template configuration item. This function is automatically called by vue, and a functioncreateElemen
will be passed over to create elements (required after creation) return)
//The default introduction here is dist/vue.runtime.esm.js (esm version is the ES6 modular version) import Vue from 'vue' //Import App component (root component) import App from './App.vue' //Close production prompt information Vue.config.productionTip = false //Create Vue instance newVue({ el : '#app', // Complete writing method render(createElement){ // Created a div element //return createElement('div', 'render function') return createElement(App) } \t // The abbreviation of arrow function, the parameter has only one omitted parentheses, and the function body has only one statement to omit {} and return render : h => h(App) })
App root component and other components
<!--App.vue--> <template> <div> <h1>App component</h1> <!-- Using components --> <X></X> <Y></Y> </div> </template> <script> // Determine the path when the component is introduced import X from './components/X.vue' import Y from './components/Y.vue' export default { //Register component components : {X, Y} } </script> <!--The rest is the same as the nested content of the component-->
Data transfer between components
Sending component (parent component)
passes data by assigning values to the sub-component tag attributes, receiving component (sub-component)
uses props configuration items to declare properties to receive parent components Data passed in
Simple reception
: props: [brand’, color’, price’]Add type restrictions when receiving (not necessary)
: props : { brand : String, color : String, price : Number}Add type restrictions (required) and default values when receiving
: props: {name: {type: Number, required: true}, age: {type: Number, default: 10}}
Create a subcomponent Car
to receive the data passed by the parent component. Whenever the parent component is re-rendered, the child component uses the value received by the properties in props
Will be reassigned, and the default value is the default value
- It is not recommended to modify the data received using props directly, because the next time the parent component is re-rendered, the properties received using prop configuration items in the child component will be reassigned.
- Generally, indirect modification of the value of an intermediate variable is used to avoid the problem of the modified value of the child component being overwritten when the parent component is re-rendered.
<template> <div> <h3>Brand: {<!-- -->{brand}}</h3> <h3>Price: {<!-- -->{cprice}}</h3> <h3>Color: {<!-- -->{color}}</h3> <button @click="add">Price plus 1</button> </div> </template> <script> export default { name: 'Car', data() { return { //Assign the value of the received price attribute to an intermediate variable cprice : this.price } }, methods : { add(){ // Modify the value of the intermediate variable. Even if the parent component is re-rendered, the modified value of the child component will not be overwritten. this.cprice++ } }, // Use the props configuration item in the Car subcomponent to dynamically receive data passed by other components, and no longer use the static data in its own configuration item data. data() { return { brand: 'BMW 520', price: 10, color: 'black' } }, // The first one: simple receiving method, directly using array reception props: ['brand','color','price'] // The second type: add type restrictions when receiving (an error will be reported if the type does not match) props : { brand: String, color: String, price :Number } // The third type: add necessary restrictions and default values of the type when receiving props : { brand : { type: String, required: true }, color : { type: String, default: 'red' }, price : { type: Number, required: true } } } </script>
Get the child component and its attributes from the parent component, and use the ref attribute
on the child component tag or the Dom element to identify it
- Get a certain subcomponent and its attributes: Use
$refs
in the current component to get all the subcomponents of the current component, and then get a specific component and its attributes through the component’s identifier. - Nested form is supported when obtaining subcomponents:
this.$refs.Component identification.$refs.name
indicates accessing the subcomponent properties of the subcomponent.
<template> <div> <!--Ordinary HTML tags can also be identified using HTML tags--> <h1 ref="hh">{<!-- -->{msg}}</h1> <!--price="10" means that the passed data is the string "10", :price="10" means that the passed data is the number 10 (attribute binding,"" 10 within is treated as a constant)--> <Car brand="BMW 520" color="black" :price="10" ref="car1"></Car> <Car brand="BYD Han" color="red" :price="20" ref="car2"></Car> <button @click="printCarInfo">Print car information</button> </div> </template> <script> import Car from './components/Car.vue' export default { name: 'App', data() { return { msg: 'Car information' } }, methods : { printCarInfo(){ // Use the $refs attribute to get child components console.log(this.$refs.car1) console.log(this.$refs.car2) \t\t\t\t //Access the properties of the subcomponent console.log(this.$refs.car1.brand) console.log(this.$refs.car1.color) console.log(this.$refs.car1.price) // You can also use the $refs attribute to obtain the value of ordinary DOM elements, replacing the operation of native Dom. console.log(this.$refs.hh.innerText) } }, components: {Car} } </script>
mixins configuration items (mixing)
If the configuration item codes of multiple xxx.vue
files are the same (the configuration items have no restrictions such as methods), you can use the mixins
configuration item for reuse.
- Step 1: Extract the same configuration items and define them separately into a
mixin.js
file, usually in the same directory as main.js - Step 2: Import the
mixin.js
file into the correspondingxxx.vue
file, and then use the exposed configuration in themixins configuration item
Configuration item conflicts during mixing
Adopt the proximity principle for common configuration items
: that is, only the component’s own configuration will be executed and mixed configurations will not be executed, because mixing means not to destroyAdopt the superposition method for the life cycle hook function
: that is, execute the mixed one first and then execute your own
There are two ways of mixing: local mixing
and global mixing
// Exposed separately export const mix1 = { methods: { printInfo(){ console.log(this.name, ',' , this.age) } } } // Ordinary configuration export const mix2 = { methods: { a(){ console.log('mixin.js a.....') } }, } // life cycle function export const mix3 = { mounted() { console.log('mixin.js mounted...') } }
Adopt the proximity principle for common configuration items
: that is, only the component’s own configuration will be executed and mixed configurations will not be executed, because mixing means not to destroy
<template> <div> <h1>{<!-- -->{msg}}</h1> <h3>Name: {<!-- -->{name}}</h3> <h3>Age: {<!-- -->{age}}</h3> <button @click="printInfo">Execute the printInfo method to print user information</button> <button @click="a">Execute method a</button> </div> </template> <script> //Import mixin configuration items import {mix1} from '../mixin.js' import {mix2} from '../mixin.js' export default { name: 'Vip', data() { return { msg: 'Member information', name: '李思2', age: 21 } }, // Partial mixing, array reception means multiple mixing can be done mixins : [mix1,mix2], // Only the own a method is called here, and the mixed a method will not be executed. methods: { a(){ console.log('vip a....') } }, } </script>
Adopt the superposition method for life cycle hook functions
: that is, execute the mixed hook function first and then execute your own hook function
<template> <div> <h1>{<!-- -->{msg}}</h1> <h3>Name: {<!-- -->{name}}</h3> <h3>Age: {<!-- -->{age}}</h3> <button @click="printInfo">Execute the printInfo method to print user information</button> <button @click="a">Execute method a</button> </div> </template> <script> //Import the mixin configuration items in the mixin.js file import {mix1} from '../mixin.js' import {mix2} from '../mixin.js' import {mix3} from '../mixin.js' export default { name: 'User', // Here the mixed mounted function is executed first, and then its own mounted function is executed. mounted() { console.log('User mounted...') }, data() { return { msg: 'User information', name: 'Zhang San 2', age: 20 } }, // Partial mixing, array reception means multiple mixing can be done mixins : [mix1,mix2, mix3], } </script>
The global mixin
configuration items in the main.js
file will be automatically imported into all components including the root component root, that is, vm
configuration items and execute them according to the rules
// Equivalent to introducing the vue.js file import Vue from 'vue' //Import App component (root component) import App from './App.vue' //Import mixin configuration items import {mix1} from './mixin.js' import {mix2} from './mixin.js' import {mix3} from './mixin.js' //Global mix-in Vue.mixin(mix1) Vue.mixin(mix2) Vue.mixin(mix3) //Close production prompt information Vue.config.productionTip = false //Create Vue instance newVue({ el : '#app', render : h => h(App) })
plugins configuration (plug-in)
Plug-in is an object
: It is used to enhance functions of Vue (pluggable). A plug-in generally corresponds to an independent function, and plug-ins are generally placed in a plugins. js
file (usually in the same directory as main.js)
The plug-in object must have an install method
. This method has two parameters and will be automatically called
- First parameter: Vue constructor
- The second parameter: the data passed by the user when using this plug-in. There is no limit to the number of parameters.
Step one: Define the plug-in object and expose it. For example, we can define a plug-in here. The function is to extend a counter attribute to the prototype object of Vue (accessible through both vm and vc)
strong>
export const p1 = {<!-- --> install(Vue, a, b, c, d){<!-- --> console.log('This plug-in is displaying a cute cover') console.log(Vue) console.log(a,b,c,d) // Get the prototype object of Vue, extend a counter attribute to the prototype object of Vue, which can be accessed through vm and vc Vue.prototype.counter = 1000 } }
Step 2: Import the created plug-in object in the main.js
file, and then use the imported plug-in
// Equivalent to introducing the vue.js file import Vue from 'vue' //Import App component (root component) import App from './App.vue' //Import plugin import {p1} from './plugins.js' // Plug in the plug-in (to delete it means to unplug the plug-in), usually before creating a Vue instance Vue.use(p1, 1,2,3,4) //Close production prompt information Vue.config.productionTip = false //Create Vue instance newVue({ el : '#app', render : h => h(App) })
Step 3: Access a counter attribute extended by the plug-in object we defined to the Vue prototype object
<template> <div> <button @click="a">Execute method a</button> </div> </template> <script> export default { methods: { a(){ console.log('vip a....') //Access the counter attribute extended by the plug-in object to the Vue prototype object console.log('A counter extended by a plug-in:', this.counter) } }, } </script>
Local style scoped
By default, the styles defined in the style tag
in all components will eventually be summarized together. If the style names are consistent, conflicts will occur. At this time, the nearest principle will be adopted, that is, the component style to be loaded later will be adopted. Subject to
- The styles in components support multiple style languages (such as css, less, sass). To use less syntax, you need to execute the
npm i less-loader
command to install less-loader.
After adding the scoped attribute
to the style tag of the component, the bottom layer of Vue will add attributes to the tag, so that even if the styles are merged together, there will be no conflict
<template> <div class="s"> <h1>{<!-- -->{msg}}</h1> </div> </template> <script> export default { data() { return { msg: 'User information', } } } </script> <!--After adding the scoped attribute to the style tag of the component, the bottom layer of Vue will add attributes to the tag, so that even if the styles are merged together, there will be no conflict--> <style scoped> .s { background-color: aquamarine; } </style>
<template> <div class="s"> <h1>{<!-- -->{msg}}</h1> </div> </template> <script> export default { data() { return { msg: 'Member information', } } } </script> <!--After adding the scoped attribute to the style tag of the component, the bottom layer of Vue will add attributes to the tag, so that even if the styles are merged together, there will be no conflict--> <style scoped> .s { background-color:bisque } </style>
The style in App root component
generally adopts the global method
and it is not recommended to add the scoped attribute. The style of the sub-component generally adds the scoped attribute
<template> <div> <User></User> <Vip></Vip> </div> </template> <script> // Import Vip first. Due to style conflict, the style of the User component will overwrite the style of the Vip component. import Vip from './components/Vip.vue' import User from './components/User.vue' export default { name: 'App', components : {User, VIP} } </script> <style> /* Generally, the style in the App root component will not be scoped, because the style of the root component still wants to be processed in a global way*/ </style>