23 Front-end engineering

23.1 Modularity related specifications

The main problem of the traditional development mode Naming conflicts file dependence by modularization solve the above problems is to make a separate function is encapsulated as a module (documents), the isolation between modules, but can be by a specific interface open internal member, also can rely on other modules, modular development benefits: Facilitate code reuse, thus improving development efficiency, and facilitate the maintenance of browser-side modular specifications1. AMD
Require.js (http://www.requirejs.cn/)
2. CMD
3.Sea. Js (https://seajs.github.io/seajs/docs/) server module specification4.Module members export: module.exports and module members import: require(' module identifier ')Copy the code

23.2 ES6 Modularization

Before the ES6 modular specification was born, the Javascript community had tried and proposed AMD, CMD, CommonJS and other modular specifications. However, the modular standards proposed by these communities still have some differences and limitations, and are not universal modular standards for browsers and servers. For example: AMD and CMD for browser-side Javascript modularity CommonJS for server-side Javascript modularity Therefore, the ES6 syntax specification defines the ES6 modularity specification at the language level, It is a common modular development specification for browser side and server side. As defined in the ES6 modularity specification: each JS file is an independent module importing module members using the import keyword exposing module members using the export keywordCopy the code

Experience ES6 modularity through Babel in 23.2.1 Node.js

1 npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node 2 npm install --save @babel/polyfill 3 Const presets = [["@babel/env", {targets: {edge: "17", firefox, "60", chrome: "67", safari: "11.1"}}]]. module.exports = { presets }; 5 Run NPX babel-node index.js to execute the codeCopy the code

23.2.2 Basic syntax for ES6 modularity

Default export syntax Export Default Default exported member Default import syntax Import Receiver name from 'module identifier' // Import module member import M1 from './m1.js' console.log(m1) // // {a: 10, c: 20, show: [Function: Function d = 30 function d = 30 () {} function d = 30 () {} Export default {a, c, show} is allowed only once in each module, otherwise an error will occur. Export let s1 = 10 Export on demand syntax import {s1} from 'module identifier' // Import module members import {s1, S2 as SS2, Say} from './m1.js' console.log(s1) aaa console.log(ss2) CCC console.log(say) Say] // The current file module is m1.js // Export variable s1 export let s1 = 'AAA' // Export variable s2 export let s2 = 'CCC' // Export method say export on demand Function say = function() {} Function say = function() {} Function say = function() {} Function say = function() {} // Execute a for loop in the current module for(let I = 0; i < 3; i++) { console.log(i) }Copy the code

23.2.3 Enhanced writing of attributes

<script>
  // const obj = new Object()

  // const obj = {
  // name: 'why',
  // age: 18,
  // run: function () {
  // console.log(' running ');
  / /},
  // eat: function () {
  // console.log(' next thing ');
  / /}
  // }

  // 1. Attribute enhancement
  const name = 'why';
  const age = 18;
  const height = 1.88

  // ES5
  // const obj = {
  // name: name,
  // age: age,
  // height: height
  // }
  / / the ES6 way
  // const obj = {
  // name,
  // age,
  // height,
  // }
  //
  // console.log(obj);


  // 2
  // ES5
  // const obj = {
  // run: function () {
  //
  / /},
  // eat: function () {
  //
  / /}
  // }
  / / the ES6 way
  const obj = {
    run(){},eat(){}}</script>
Copy the code

23.3 webpack

Webpack is a popular front-end project building tool (packaging tool) that addresses the dilemmas of current Web development. Webpack provides friendly modularization support, as well as code compression confusion, dealing with JS compatibility problems, performance optimization and other powerful functions, so that programmers put the focus of work on the specific function implementation, improve the development efficiency and maintainability of the project. At present, most of the front-end projects in enterprises are packaged and built based on WebPack.Copy the code

23.3.1 Basic use of Webpack

1.Create list interlaced color changing items-Create a blank directory for the project and run NPM init -y to initialize the package.json configuration file-Create a new SRC source directory-Create a new SRC -> index.html home page-Initialize the basic structure of the home page-Run NPM install jquery -s to install jquery-Through the modular form, realize the list interlaced color effect2.Install and configure WebPack in your project-Run the NPM install webpack webpack-cli -d command to install webpack-related packages-In the project root, create a webpack configuration file called webpack.config.js-In the webpack configuration file, initialize the following basic configuration: module.exports = {mode: {"dev": {"dev": {"dev": {"dev": } ⑤ Run the NPM run dev command in the terminal to start webpack for project packaging. The default convention in the 4.x version of Webpack is that the packaged entry file is SRC -> index.js and the packaged output file is dist -> main.js to modify the packaged entry and exit, you can add the following configuration information in webpack.config.js: // Imports module.exports = {entry: path.join() const path = require('path') // Imports module.exports = {entry: path.join()__dirname, './ SRC /index.js'), // The path to package the entry file output: {path: path.join(__Filename: 'bundle.js'; filename: 'bundle.js';4.Configure automatic packaging for WebPack-Run the NPM install webpack-dev-server -d command to install the tool that supports automatic project packaging-Json -> scripts dev command: "scripts": {"dev": "webpack-dev-server" // scripts under the node, can be run through NPM run}-SRC -> index. HTML "/buldle.js"-Run the NPM run dev command to repackage-Visit http://localhost:8080 in your browser to view the effect of automatic packaging. Note: Webpack-dev-server launches a live packaged HTTP server. The output generated by the webpack-dev-server package is placed in the project root directory by default, and is virtual and invisible5.Configure html-webpack-plugin to generate preview pages-Run the NPM install html-webpack-plugin -d command to install the plug-in that generates the preview page-Modify the webpack.config.js header and add the following configuration information: // Import the plugin that generates the preview page, Const HtmlWebpackPlugin = require('html-webpack-plugin') const htmlPlugin = new HtmlWebpackPlugin({//) Create an instance object for the plugin, template: './ SRC /index.html', // specify a template file named filename to use: 'index.html' // specify the name of the generated file, which exists in memory and is not displayed in directory}) ③ Modify the configuration object exposed in the webpack.config.js file, add the following configuration node: Module.exports = {plugins: [htmlPlugin] // plugins array is a list of plugins used during webpack}6.Configure parameters related to automatic packaging // package.json configuration // --open Automatically opens the browser page after the packaging is complete // --host configure the IP address // --port Configure the port "scripts": {"dev": "Webpack-dev-server --open --host 127.0.0.1 --port 8888"}, loader in webpack1.In the actual development process, Webpack can only package modules ending with.js suffix by default, and other modules ending with non-.js suffix cannot be processed by webpack by default, and can be normally packaged only by invoking loader. Otherwise an error will be reported! Loader can help WebPack handle specific file modules, such as: Less-loader can package the files related to less. Sass-loader can package the files related to SCSS. Url-loader can package the files related to URL paths in the CSSCopy the code

23.3.2 Invoking Process of Loader

23.3.2.1 Basic use of loaders in loaderWebPack
1.Package and process CSS files-Run the NPM I style-loader css-loader -d command to install the loader that processes CSS files-Add loader rules to webpack.config.js module -> rules array as follows: // Matching rules for all third party file modules module: {rules: [{test: /\.css$/, use: ['style-loader', 'css-loader']}]} Test indicates the file type, use indicates the loader to be invoked. The sequence of loaders specified in the use array is fixed. The sequence of multiple Loaders is called from back to front2.Package and process less files-Run the NPM I less-loader less -d command-Add loader rules to webpack.config.js module -> rules array as follows: // Matching rules for all third party file modules module: {rules: [{test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] } ] }3.Package and process SCSS files-Run the NPM I sass-loader node-sass -d command-// Match rules for all third party file modules module: {rules: [{test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] } ] }4.Configure postCSS To automatically add the CSS compatible prefixes-Run the NPM I postcss-loader autoprefixer -d command-Create the postcss configuration file postcss.config.js in the project root directory and initialize the following configuration: Module. Exports = {plugins: [autoprefixer] // import plugins from module. Exports = {plugins: [autoprefixer] // import plugins from module.-Module: {rules: [{test:/\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader'] } ] }5.Package the image and font files in the stylesheet-Run the NPM I url-loader file-loader -d command-Add loader rules to webpack.config.js module -> rules array as follows: module: {rules: [{test: / \. JPG | PNG | | GIF BMP | the vera.ttf | eot | SVG | woff | woff2 $/, use: 'url - loader? Limit = 16940'}}]? After is the parameters of the loader. Limit specifies the size of an image, in bytes. Only images smaller than the limit size are converted to Base646.Package handles advanced syntax in JS files-NPM I babel-loader @babel/ core@babel/run-time -d-NPM I @babel/preset-env @babel/plugin- transformRuntime @babel/plugin-proposal-class-properties -- D-In the project root directory, create the Babel configuration file babel.config.js and initialize the base configuration as follows: module.exports = {presets: ['@babel/preset-env'], plugins: ['@babel/plugin-transform-runtime', '@babel/plugin-proposalclass-properties']}-// exclude indicates that babel-loader does not need to process nodeJs files in _modules {test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
Copy the code

23.3.3 Vue single file component

Component structure of single file components Template component template area Script business logic area Style area<template><! This is used to define the template content of the Vue component.</template>
 <script>Export default {data: () {return {}}, // Private data methods: {} // processing functions //... Other business logic}</script>
 <style scoped>
 /This is used to define the style of the component/
 </style>Webpack configures the loader for vUE components-Run the NPM I vue-loader vue-template-compiler -d command-In the webpack.config.js configuration file, add the following configuration items for vue-loader: Export.exports = {module: {rules: [//... export.exports = {rules: [//... /\.vue$/, loader: 'VueLoaderPlugin'}]}, plugins: [//... } Use VUE in webPack projects-Run NPM I vue -- S to install vUE-In the SRC -> index.js entry file, import the Vue constructor by importing Vue from 'Vue'-Create an instance object of vUE and specify the EL region to control-Vue constructor import Vue from 'Vue' // 2. /components/ app. vue' const vm = new vue ({// 3. Specify the page area that the vm instance controls el: '#app', // 4. Render the specified component into the RENDER el area using the render function: H => h(App)}) webpack The application needs to be packaged in webpack before it is released online. You can configure the packaging command in package.json file: // This command loads the webpack.config.js configuration file "scripts" in the root directory of the project by default: {// The command "build" for packaging: Dev: "webpack-dev-server --open --host 127.0.0.1 --port 3000",},Copy the code

24 Vue CLI Scaffolding

24.1 What is the CLI

The command line interface (CLI) was the most widely used user interface before the popularization of the GRAPHICAL user interface (GUI). It usually does not support the mouse. Users input commands through the keyboard, and the computer executes the commands after receiving them. Some call it CUI (Character User Interface)Copy the code

24.2 What is the Vue CLI

Vue CLI is a complete system for rapid development based on Vue. Js. Using Vue scaffolding, the page we developed would be a complete system.Copy the code

24.3 Vue CLI Advantages

-Build interactive project scaffolding through VUE-CLI. Bootstrap CSS JS jquery JS You can download related dependencies by running commands-Vuejs vuerouter axios(one command) Quick start zero configuration prototype development vue page via @vue/cli + @vue/cli-service-global-A runtime dependency (@vue/cli-service) that:  -Can upgrade A command  -Built on WebPack with reasonable default configuration; Webpack project package compiled project source === => deployed to the server for direct use  -It can be configured through the configuration file in the project; The default configuration file, by modifying the default configuration file to achieve their desired project environment  -Extensions can be made through plug-ins. vue v-charts elementui-A rich collection of official plug-ins that integrate the best tools in the front-end ecosystem. Nodejs(tomcat) Vue VueRouter webpack yarn-A fully graphical user interface for creating and managing vue.js projectsCopy the code

24.4 Vue CLI Installation

24.4.1 Environment Preparation
24.4.1.1 NPM uses domestic images
Command / / set up taobao source NPM config set registry HTTP: / / https://registry.npm.taobao.org / / setting the company's source of NPM config set registry http://127.0.0.1:4873 // View the source, Can see set all of the source of NPM config get registry by using CNPM installation NPM install - g CNPM use CNPM - registry=https://registry.npm.taobao.org cnpm install xxxCopy the code
1. Download the nodejsWindows system: http://nodejs.cn/download/. Msi installation package (exe) designated installation location. Zip (zip) direct decompression MAC OS system specified directory: .pkg Installation package format Automatically configures the environment variable.tar.gz(compressed package)2. Configure the nodeJS environment variableWindows: 1. Right-click properties ----> Advanced properties ----> Environment Variables and add the following configuration: NODE_HOME= NodeJS installation directory PATH = XXXX; %NODE_HOME% 2. Macos This parameter is recommended. PKG Installation Directly configure node environment 3. Check whether the NodeJS environment is successful node -v 4. NPM Introduction Node Package Mangager NodeJS Package management tool Front-end mainstream technology NPM centralized management Maven management Java backend relies on remote repository (central repository) Ali Cloud image NPM Management front-end system relies on remote warehouse (central warehouse) to configure Taobao mirror 5. Configuration taobao mirror NPM config set registry https://registry.npm.taobao.org NPM config get registry6. Configure the NPM download dependency locationwindows: npm config set cache "D:\nodereps\npm-cache" npm config set prefix "D:\nodereps\npm_global" mac os: npm config set cache "/Users/chenyannan/dev/nodereps" npm config set prefix "/Users/chenyannan/dev/nodereps"7. Verify the NodeJS environment configurationnpm config ls ; userconfig /Users/chenyannan/.npmrc cache = "/Users/chenyannan/dev/nodereps" prefix = "/Users/chenyannan/dev/nodereps" registry = "https://registry.npm.taobao.org/"
Copy the code
24.4.2 Scaffolding installation
X NPM install vue-cli -g 3.x NPM install -g@vue /cli# OR yarn global add @vue/cliNode. js and NPM have been installed on your PC. Uninstall VUe-cli (1.x or 2.x) NPM uninstall vue-cli -g or YARN Global remove VUe-CLI Uninstalling CLI3 NPM Uninstall -g@vue/CLI or YARN Global remove@vue/CLI Upgrade To upgrade the global Vue CLI package, run the NPM update -g@vue /cli command# orYarn Global upgrade --latest @vue/ CLI Solve the problem of slow NPM download. Use the CNPM command line tool customized on Taobao to replace the default installation of NPM NPM install -g CNPM - registry=https://registry.npm.taobao.org create vue - cli2 project vue init webpack project name Create a vue graphical interface - cli3 project create project vue UI NPM run dev scaffolding 3 NPM run serve scaffolding 2 package NPM run build # NPM build file scaffolding 3 package NPM run build Because you finally gave the package file directly, directly test before handing over, run the package file, check whether the project is complete scaffolding 3Copy the code
24.4.3 First VUE scaffolding project
1. Create the first project of vUE scaffoldingVue init webpack project name 2. Create the first project hello -------------> project name -build -------------> to use webpack package using build dependency -config -- -- -- -- -- -- -- -- -- -- -- -- -- > used to do the whole project configuration directory - node_modules -- -- -- -- -- - > used to manage projects use dependency - SRC -- -- -- -- -- - > writing vue source code [key] + assets -- -- -- -- -- - > used to store static resource [key] Components used to write -- -- -- -- -- - > the Vue components [key] the router -- -- -- -- -- - > the path [key] App. Used to configure the project Vue -- -- -- -- -- - > project root. [key] the main component of js -- -- -- -- -- - > project main entry [key] - static -- -- -- -- -- - > other static - babelrc -- -- -- -- -- - > will turn es5 running es6 grammar - editorconfig -- -- -- -- -- - edit configuration - > project. Gitignore -- -- -- -- -- - > the git version control ignore files -.postcsrc. Js ------> source code related js-index.html ------> project home -package.json ------> Similar to PAM.xml dependency management jquery Manual modification is not recommended -package-lock.json ----> Lock package.json - readme. md ----> Project Description file3. How to run execution in the root directory of the project		npm run dev
4. How do I access the project		http://localhost:8081    
5.Vue Cli project development modeVueCli's development method is to develop a business function module corresponding to one component in the project. In the future, multiple components can be combined together to form a front-end system. In the future, when using the Vue Cli for development, instead of writing HTML, you will write component by component (the file ending with the suffix. Vue), and the Vue Cli will compile the component into running HTML files when packagingCopy the code
24.4.4 How to develop Vue scaffolding
Note: In the Vue CLI everything is a componentCopy the code
24.4.5 Custom configuration of Vue scaffolding
1."Vue ": {"devServer": {"port": "8888", "open" : true}}. Note: This configuration is not recommended. Because package.json is mainly used to manage package configuration information; For easy maintenance, you are advised to define the configurations related to vue pins in the vue.config.js configuration file.2.Configure the project through a separate configuration file-Create the file vue.config.js in the project directory-Exports = {devServer: {port: 8888}} // vue.config.js module.exports = {devServer: {port: 8888}}Copy the code

25 Use Axios in scaffolding

25.1 installation axios

# 1. Install AXIOS
	npm install axios --save-dev

# 2. Configure main.js to include AXIos
	import axios from 'axios';

	Vue.prototype.$http=axios;

# 3. Use Axios
In the position of the need to send an asynchronous request, enclosing $HTTP. Get (" url "). Then ((res) = > {}) enclosing $HTTP. Post (" url "). Then ((res) = > {})Copy the code

26 Elemental – Basic use of UI

Element-ui: A Vue 2.0-based desktop component library for developers, designers, and product managers. The official website is http://element-cn.eleme.io/#/zh-CN1.Manual installation based on the COMMAND line-Install the dependency package NPM I element-ui -- S-Import ElementUI from 'element-ui'; Import 'elemental-ui /lib/theme-chalk/index.css'; // Configure Vue plugin Vue. Use (ElementUI);2.Automatic installation based on graphical interface-Run the vue UI command to open the GUI-Through Vue Project Manager, enter the specific project configuration panel-Click Plug-in -> Add Plug-in to enter the plug-in query panel-Search vuE-cli-plugin-element and install it-Configure plug-ins for on-demand imports to reduce the volume of packaged projectsCopy the code

27 Vuex

27.1 How to share data between components

Parent to child: V-bind Child to parent: V-ON Event binding Data shared between siblings: EventBus-$on The component that receives the data-The component that $emit sends data to but this scope is small and not easy to maintain, so vuex was born.Copy the code
Vuex is a mechanism to implement global state (data) management of components and facilitate data sharing among components.Copy the code

27.2 Vuex Enables data sharing between components

Benefits of unified state management using Vuex-Centralized management of shared data in VUEX for easy development and maintenance-It can efficiently realize data sharing between components and improve development efficiency-The data stored in VUEX is responsive and can be synchronized with the page in real time. What kind of data is suitable for storing in VUEX? Generally, only the data shared between components is necessary to store in VUEX. For private data in the component, it is still stored in the component's own data.Copy the code

27.3 Basic use of Vuex

1.Install vuex dependency package NPM install vuex --save2.Import vuex from 'vuex' vue.use (vuex)3.Const store = new vuex. store ({// state: {count: 0}})4.New vue ({el: '#app', render: Vue => router, Vue => router, Vue => router, Vue => routerCopy the code

27.3.1 counter

App.vue

<template>
  <div>
    <my-addition></my-addition>

    <p>---------------------------------</p>

    <my-subtraction></my-subtraction>
  </div>
</template>

<script>
import Addition from './components/Addition.vue'
import Subtraction from './components/Subtraction.vue'

export default {
  data() {
    return{}},components: {
    'my-addition': Addition,
    'my-subtraction': Subtraction
  }
}
</script>

Addition.vue
<template>
  <div>
    <! - < h3 > the latest count value is: {{$store. State. The count}} < / h3 > -- >
    <h3>{{$store.getters.showNum}}</h3>
    <button @click="btnHandler1">+ 1</button>
    <button @click="btnHandler2">+N</button>
    <button @click="btnHandler3">+1 Async</button>
    <button @click="btnHandler4">+N Async</button>
  </div>
</template>

<script>
export default {
  data() {
    return{}},methods: {
    btnHandler1() {
      this.$store.commit('add')},btnHandler2() {
      // commit calls a mutation function
      this.$store.commit('addN'.3)},// Asynchronously increment count by +1
    btnHandler3() {
      // The dispatch function here is specifically used to trigger the action
      this.$store.dispatch('addAsync')},btnHandler4() {
      this.$store.dispatch('addNAsync'.5)}}}</script>

Subtraction.vue
<template>
  <div>
    <! {{count}}</h3> -->
    <h3>{{showNum}}</h3>
    <button @click="btnHandler1">- 1</button>
    <button @click="subN(3)">-N</button>
    <button @click="subAsync">-1 Async</button>
    <button @click="subNAsync(5)">-N Async</button>
  </div>
</template>

<script>
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'

export default {
  data() {
    return{}},computed: {
    ...mapState(['count']),
    ...mapGetters(['showNum'])},methods: {
    ...mapMutations(['sub'.'subN']),
    ...mapActions(['subAsync'.'subNAsync']),
    btnHandler1() {
      this.sub()
    }
  }
}
</script>store.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { count: Mutations only the function defined in mutations has the right to modify the data mutations in state: {add(state) {// Do not open the mutations function, // setTimeout(() => {// state.count++ //}, 1000) state.count++}, addN(state, step) {state.count+ = step}, sub(state) { state.count-- }, subN(state, step) { state.count -= step } }, actions: {addAsync(context) {setTimeout(() => {// In actions, you cannot directly modify data in state; Context.mit ('add')}, 1000)}, addNAsync(context, step) { setTimeout(() => { context.commit('addN', step) }, 1000) }, subAsync(context) { setTimeout(() => { context.commit('sub') }, 1000) }, subNAsync(context, step) { setTimeout(() => { context.commit('subN', step) }, 1000) } }, getters: {showNum(state) {return 'The current number is [' + state.count +'] '}}}) main.js import Vue from 'Vue' import App from './App.vue' import store from './store' Vue.config.productionTip = false new Vue({ store, render: h => h(App) }).$mount('#app')Copy the code

27.4 Core concepts of Vuex

State
Mutation
Action
Getter
Copy the code
State Provides a unique common data source. All shared data must be stored in the Store State. Const store = new vuex. store ({state: {count: 0}}) Const store = new vuex. store ({state: {count: 0}}) A second way for global data name components to access data in State: // 1. Import {mapState} from 'vuex' Use the mapState function you just imported to map global data needed by the current component to computed properties of the current component: // 2. Map global data to the computed property of the current component, computed: {... MapState (['count'])} Mutation is used to change data in the Store.-Store data can only be changed by mutation, but data in Store cannot be manipulated directly.-This is a slightly more cumbersome way to operate, but you can monitor all data changes centrally. Mutations const store = new vuex. store ({state: {count: 0}, mutations: {add(state) {// state of the change state.count++}}}) {handle1() {this. codestore.mit ('add')}} specifies Mutation const store = new when mutations are triggered  Vuex.Store({ state: { count: 0 }, mutations: AddN (state, step) {// change status state.count += step}}}) {handle2() {// When calling commit, Use this. codestore.com MIT ('addN', 3)}} This. codestore.com MIT () is the first way to trigger mutations, and the second way to trigger mutations: / / 1. Mutations import {mapMutations} from 'vuex' on demand, and the mutations function, Mapping to current component's methods: // 2. Map the specified mutations function to the methods function of the current component (methods: {... MapMutations (['add', 'addN'])} Action Action is used to handle asynchronous tasks. If the data is changed by an asynchronous operation, it must be changed through an Action rather than Mutation, but the data must be changed indirectly by triggering Mutation in the Action. // define Action const store = new vuex.store ({//... Mutations: {add(state) {state.count++}}, actions: {addAsync(context) {setTimeout(() => {context.com MIT ('add')}, 1000)}} {handle() {this.$store.dispatch('addAsync')}}}) triggers actions with arguments: // define Action const store = new vuex.store ({//... Mutations: {addN(state, step) {state.count += step}}, actions: {addNAsync(context, step) {setTimeout(() => {context.com MIT ('addN', step)}, 1000)}}}) {handle() {// Call the dispatch function, $store. Dispatch ('addNAsync', 5)}} This.$store. Dispatch () is the first way to trigger actions. Second way to trigger actions: // 1. Import {mapActions} from 'vuex'. Map the required actions to the current component's methods: / / 2. Map the actions function to the current component's methods function (methods: {... MapActions (['addASync', 'addNASync'])} Getter Getter is used to process data in the Store to form new data.-Getters can process existing data in the Store to form new data, similar to the calculation properties of Vue.-As the data in the Store changes, so does the data in the Getter. // define Getter const store = new vuex. store ({state: {count: 0}, getters: {showNum: State => {return 'current count is ['+ state.count +']'}}}) the first way to use getters: this.$store.getters. A second way to use getters for names: import {mapGetters} from 'vuex' computed: {... mapGetters(['showNum']) }Copy the code

27.5 Case based on Vuex

Todos
Copy the code

1.Initialize the project implementation steps-Use the Vue UI command to open the visual panel and create a new project vuex-Demo2-NPM install vuex axios ant-design-vue -- S-Implement Todos basic layout (based on existing style templates)2.Complete specific functions-Load task list data dynamically-Realize bidirectional synchronization between text box and store data-The operation of adding a task is complete-The task is deleted-The dynamic bind check box is checked-Modify the completion status of a task item-Count the number of unfinished tasks-Clear completed tasks-Realize the dynamic switch of task list dataCopy the code
App.vue
<template>
  <div id="app">
    <a-input placeholder="Please enter the task" class="my_ipt" :value="inputValue" @change="handleInputChange" />
    <a-button type="primary" @click="addItemToList">To add</a-button>

    <a-list bordered :dataSource="infolist" class="dt_list">
      <a-list-item slot="renderItem" slot-scope="item">
        <! -- Check box -->
        <a-checkbox :checked="item.done" @change="(e) => {cbStatusChanged(e, item.id)}">{{item.info}}</a-checkbox>
        <! -- Delete link -->
        <a slot="actions" @click="removeItemById(item.id)">delete</a>
      </a-list-item>

      <! -- Footer area -->
      <div slot="footer" class="footer">
        <! -- Number of unfinished tasks -->
        <span>{{unDoneLength}} a surplus</span>
        <! -- Operation button -->
        <a-button-group>
          <a-button :type="viewKey === 'all' ? 'primary' : 'default'" @click="changeList('all')">all</a-button>
          <a-button :type="viewKey === 'undone' ? 'primary' : 'default'" @click="changeList('undone')">unfinished</a-button>
          <a-button :type="viewKey === 'done' ? 'primary' : 'default'" @click="changeList('done')">Has been completed</a-button>
        </a-button-group>
        <! -- Clear the list of completed tasks -->
        <a @click="clean">Cleanup complete</a>
      </div>
    </a-list>
  </div>
</template>

<script>
import { mapState, mapGetters } from 'vuex'

export default {
  name: 'app'.data() {
    return{}},created() {
    this.$store.dispatch('getList')},computed: {
    ...mapState(['inputValue'.'viewKey']),
    ...mapGetters(['unDoneLength'.'infolist'])},methods: {
    // Listen for text box content changes
    handleInputChange(e) {
      this.$store.commit('setInputValue', e.target.value)
    },
    // Add an item to the list
    addItemToList() {
      if (this.inputValue.trim().length <= 0) {
        return this.$message.warning('Text box contents cannot be empty! ')}this.$store.commit('addItem')},// Delete the corresponding task according to the Id
    removeItemById(id) {
      // console.log(id)
      this.$store.commit('removeItem', id)
    },
    // Listen for events whose status changes
    cbStatusChanged(e, id) {
      // e.target.checked accepts the latest checked status
      // console.log(e.target.checked)
      // console.log(id)
      const param = {
        id: id,
        status: e.target.checked
      }

      this.$store.commit('changeStatus', param)
    },
    // Clear completed tasks
    clean() {
      this.$store.commit('cleanDone')},// Modify the list data displayed on the page
    changeList(key) {
      // console.log(key)
      this.$store.commit('changeViewKey', key)
    }
  }
}
</script>

<style scoped>
#app {
  padding: 10px;
}

.my_ipt {
  width: 500px;
  margin-right: 10px;
}

.dt_list {
  width: 500px;
  margin-top: 10px;
}

.footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
</style>store.js import Vue from 'vue' import Vuex from 'vuex' import axios from 'axios' Vue.use(Vuex) export default new Vuex.Store({state: {// all tasks list: [], // contents of text box inputValue: 'aaa', // nextId nextId: 5, viewKey: 'all' }, mutations: {initList(state, list) {state.list = list}, // setInputValue in store to setInputValue(state, Val) {state.inputValue = val}, // Add list item addItem(state) {const obj = {id: state.nextid, info: state.inputValue.trim(), done: False} state.list.push(obj) state.nextid ++ state.inputValue = ""}, // Remove the corresponding task item removeItem(state, Const I = state.list.findIndex(x => xID === id) const I = state.list.findIndex(x => xid === id) const I = state.list.findIndex(x => xid === id) == -1) {state.list.splice(I, 1)}}, param) { const i = state.list.findIndex(x => x.id === param.id) if (i ! == -1) { state.list[i].done = param.status } }, CleanDone (state) {state.list = state.list.filter(x => x.done === false)}, ChangeViewKey (state, key) {state.viewKey = key}}, actions: { getList(context) { axios.get('/list.json').then(({ data }) => { // console.log(data) context.commit('initList', data) }) } }, getters: UnDoneLength (state) {return state.list.filter(x => x.de one === = false).length}, infolist(state) { if (state.viewKey === 'all') { return state.list } if (state.viewKey === 'undone') { return state.list.filter(x => ! x.done) } if (state.viewKey === 'done') { return state.list.filter(x => x.done) } return state.list } } }) main.js import Vue from 'vue' import App from './App.vue' // 1. Import Antd from 'ant-design-vue' // 2. Import 'ant-design-vue/dist/antd. CSS 'import store from './store.js' vue.config. productionTip = false // 3. Use (Antd) new Vue({render: h => h(App), store}).$mount('# App ')Copy the code

Vue3

28 Comparison of responsive principles between Vue2.0 and VUe3.0

The Object. DefineProperty method in ES5 is used to implement reactive data in Vue2.0. Disadvantages: Unable to detect dynamic addition and deletion of Object attributes; unable to detect changes in array subscript and length attributes Vue2.0 provides vuue. Set method for dynamically adding attributes to objects Vue2.0 provides vuue. Delete method for dynamically deleting attributes of objectsCopy the code
01-Object.defineproperty
Copy the code
<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      // Vue does a data hijacking, monitoring data changes and updating the DOM once the data changes
      const data = {
        name: 'zs'.age: 18
      }

      for (let k in data) {
        let temp = data[k]
        Object.defineProperty(data, k, {
          get() {
            console.log('I hijacked it${k}Obtaining `)
            return temp
          },
          set(value) {
            console.log('I hijacked it${k}Set the value of${value}`)
            temp = value
          }
        })
      }

      // Object.defineProperty has drawbacks
      // 1. The change and deletion of the new attribute cannot be monitored
      // 2. Unable to hijack array index and length
    </script>
  </body>
</html>

Copy the code
Responsive data in 02-VUe2Copy the code
<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <h1>An example of vue</h1>
      <p>{{car.brand}} --- {{car.color}} ---{{car.price}}</p>
      <p>{{arr}}</p>
    </div>
    <script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
    <script>
      // Vue requires the $set method to dynamically add a reactive attribute
      const vm = new Vue({
        el: '#app'.data: {
          car: {
            brand: 'Mercedes'.color: 'blue'
          },
          arr: ['Joe'.'bill']}})</script>
  </body>
</html>

Copy the code

29 Vue3.0 Responsive Principle

Vue3.0 uses the proxy syntax in ES6 to implement reactive data. Advantage: Dynamic addition and deletion of proxy object attributes can be detected. Change of array subscript and length attributes can be detected. IE11 Vue3.0 has a special version for IE11 to support IE11Copy the code
03-ES6 proxy syntax. HTMLCopy the code
<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Document</title>
  </head>
  <body>
    <div></div>
    <script>
      const data = {
        name: 'zs'.age: 18
      }
      // Monitor dynamically added attributes and deleted attributes of objects
      // proxy
      const proxyData = new Proxy(data, {
        get(target, name) {
          console.log(` detected${name}Obtaining `)
          return target[name]
        },
        set(target, name, value) {
          console.log(` detected${name}Is set to${value}`)
          target[name] = value
        },
        deleteProperty(target, key) {
          console.log('Deletion detected${key}`)
          return delete target[key]
        }
      })
    </script>
  </body>
</html>

Copy the code
The principle of responsivity in 04-VUe3Copy the code
<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <h1>An example of vue</h1>
      <p>{{car.brand}} --- {{car.color}} ---{{car.price}}</p>
      <p>{{arr}}</p>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
      const App = {
        data() {
          return {
            car: {
              brand: 'BMW'.color: 'green'
            },
            arr: ['Joe'.'bill']}},methods: {
          fn() {
            this.brand = 'Mercedes'
            this.brand = 'Mercedes'
            // The DOM is updated before the callback is executed
            nextTick(function () {
              // Vue does not update the DOM immediately after data changes for performance reasons
              console.log(document.querySelector('p').innerHTML)
            })
          }
        }
      }
      const vm = Vue.createApp(App).mount('#app')
    </script>
  </body>
</html>

Copy the code

30 Create a Vue3.0 project

Install vuE-CLI to the latest version (must be later than 4.5.0) NPM init vuite-app<project-name>
cd  <project-name>
npm install 
npm run dev
Copy the code

Use of Composition API

The advantages of the Options API are that it is easy to learn and use, and the code has a clear location to write. The disadvantages of the Options API are that similar logic is not easy to reuse, especially in large projects. The Options API can extract the same logic through mixins, but it is easy to name conflicts and have unclear origins. Composition API Composition API organizes code according to logical functions. All the API Composition apis improve code readability and maintainability. The Composition API is recommended in Vue3.0, and options API is retained.Copy the code

31.1 setup

The Setup function is a new component option that serves as a starting point for the composition API in the component. From a lifecycle hook perspective, Setup will execute before the beforeCreate hook functionCopy the code
<template>
  <div class="app"></div>
</template>

<script>
export default {
  setup() {
    // Entry to the Composition API
    // Cannot access this
    console.log('Setup executes')
    console.log(this)},beforeCreate() {
    console.log('beforeCreate')}}</script>

<style></style>

Copy the code

31.2 reactive

Reactive functions take a common object and return a Reactive proxy for that object.Copy the code

<template>
  <div class="app">
    <div>{{ car.brand }}----{{ car.price }}</div>
    <button @click="Car. Brand = 'Mercedes-Benz '">Modify the</button>
  </div>
</template>

<script>
import { reactive } from 'vue'
export default {
  setup() {
    // 1. Setup requires a return value to be used in the template
    Reactive passes in a normal object and returns a proxy object
    // 3. Common objects are not reactive and need to be reactive
    const car = reactive({
      brand: 'BMW'.price: 100
    })

    return {
      car
    }
  }
}
</script>

<style></style>

Copy the code

31.3 ref

The ref function takes a value of a simple type and returns a mutable ref object. In the setup function, the value of the ref object can be accessed through the value of the ref object. In the template, the ref attribute is unnested automatically, no additional value is required. Value If a ref accepts an object, reactive is calledCopy the code
<template>
  <div class="app">
    <div>My money: {{money}}</div>
    <button @click="money++">Modify the</button>
  </div>
</template>

<script>
import { reactive, ref } from 'vue'
export default {
  setup() {
    The 1.ref function takes a simple type and returns a responsive object
    // 2. This reactive object has only one attribute value
    // 3. If ref is used in the template, ,,,, is automatically unwrapped and value is automatically called
    let money = ref(100)

    money.value++
    return {
      money
    }
  }
}
</script>

<style></style>

Copy the code

31.4 toRefs

To convert a Reactive object into a normal object, each property of the Reactive object is a Ref Reactive. However, when the object is deconstructed or expanded, the Reactive ability of the data will be lost. Using toRefs ensures that every property that the object expands is reactiveCopy the code
<template>
  <div class="app">
    <div>My money: {{money}}</div>
    <div>{{ car.brand }} --- {{ car.price }}</div>
    <div>{{ name }}</div>
    <button @click="money++">Modify the</button>
    <button @click="name = 'ls'">Modify the</button>
  </div>
</template>

<script>
import { reactive, ref, toRefs } from 'vue'
export default {
  setup() {
    // 1. toRefs
    // const money = ref(100)
    // const car = reactive({
    // brand: BMW,
    // price: 1000000
    // })
    // const name = ref('zs')

    const state = reactive({
      money: 100.car: {
        brand: 'BMW'.price: 1000000
      },
      name: 'zs'
    })

    return {
      // money,
      // car,
      // name. toRefs(state) } } }</script>

<style></style>

Copy the code

32 readOnly

Passing in an object (reactive or plain) or ref returns a read-only proxy of the original object. A read-only proxy is "deep" and any nested properties inside an object are also read-only. Can prevent objects from being modifiedCopy the code
<template>
  <div class="app">
    <div>My money: {{money}}</div>
    <div>{{ car.brand }} ---{{ car.price }}</div>
    <button @click="money++">button</button>
    <button @click="car.price = 200">button</button>
  </div>
</template>

<script>
import { reactive, ref, toRefs, readonly } from 'vue'
export default {
  setup() {
    const money = ref(100)

    const car = readonly({
      brand: 'zs'.price: 18
    })

    return {
      money: readonly(money),
      car
    }
  }
}
</script>

<style></style>

Copy the code

33 computed

Computed functions are used to create a Computed property. If you pass in a getter function, it returns a Computed property that is not allowed to be modified. If you pass in an object with a getter and setter function, it returns a Computed property that is allowed to be modifiedCopy the code
<template>
  <div class="app">
    <div>My age:<input type="text" v-model="age" /></div>
    <div>My age next year:<input type="text" v-model="nextAge" /></div>
    <div>My age the year after next:<input type="text" v-model="nextAge2" /></div>
  </div>
</template>

<script>
import { ref, computed } from 'vue'
export default {
  setup() {
    // Computed attribute usage
    const age = ref(18)

    // Computed is a function
    // 1. Pass in a function getter to return a calculated property that cannot be modified.
    const nextAge = computed(() = > {
      return parseInt(age.value) + 1
    })

    // 2. Pass in an object, including get and set, to create a calculated property that can be modified
    const nextAge2 = computed({
      get() {
        return parseInt(age.value) + 2
      },
      set(value) {
        age.value = value - 2}})return {
      age,
      nextAge,
      nextAge2
    }
  }
}
</script>

<style></style>

Copy the code

34 watch

The Watch function takes three arguments. Parameter 1: data source, which can be ref or getter function parameter 2: callback function parameter 3: Additional options, immediate and deep Watch can listen on a ref or a getter function with a return value. Watch can listen on a single data source, or multiple data sources. The Watch function returns a value to stop listening.Copy the code
<template>
  <div class="app">
    <div>{{ money }}</div>
    <div>{{ car.brand }}</div>
    <button @click="money++">button</button>
    <button @click="Car. Brand = 'Mercedes-Benz '">Button 2</button>
  </div>
</template>

<script>
import { ref, toRefs, watch, reactive } from 'vue'
export default {
  setup() {
    const state = reactive({
      money: 100.car: {
        brand: 'BMW'}})// Accept three arguments
    // Parameter 1: The monitoring data source can be a ref or a function
    // Argument 2: callback function (value, oldValue) =>{}
    // Parameter 3: Additional configuration is an object {deep: true, immediate: true}
    // watch(
    // () => state.money,
    // (value, oldValue) => {
    // console.log('money changed ', value, oldValue)
    / /}
    // )

    // watch(money, (value, oldValue) => {
    // console.log('money changed ', value, oldValue)
    // })

    // watch(
    // () => state.car,
    // (value) => {
    // console.log(' car changed ', value)
    / /},
    / / {
    // deep: true,
    // immediate: false
    / /}
    // )
    // watch([() => state.money, () => state.car], ([money, car]) => {
    // console.log(' data changed ', money, car)
    // })

    watch(
      state,
      (value) = > {
        console.log('The data has changed', value)
      },
      {
        deep: true})// watch is used to implement listening
    return {
      ...toRefs(state)
    }
  }
}
</script>

<style></style>

Copy the code

35 Lifecycle hook functions

Vue3 provides lifecycle hook registration functions that can only be compared with vue2 during setup() synchronouslyCopy the code

36 Dependency Injection

Vue3 provides provide and Inject for dependency injection to implement communication between components. Similar to provide and Inject in VUe2, provide and inject in Vue3 can be used to communicate across multiple levels of componentsCopy the code
<template>
  <div class="app">
    <h1>Hook function ----{{money}}</h1>
    <button @click="money++">button</button>
    <hr />
    <Demo :money="money"></Demo>
  </div>
</template>

<script>
import Demo from './Demo.vue'
import { ref, provide } from 'vue'
export default {
  components: {
    Demo
  },
  setup() {
    / / the provider and inject
    const money = ref(100)

    // scope problem in js
    const changeMoney = (n) = > {
      console.log(money)
      money.value = n
    }

    // The component provides the money property
    provide('money', money)
    provide('changeMoney', changeMoney)
    return {
      money
    }
  }
}
</script>

<style></style>

Copy the code

37 template refs

To get a reference to an element or component instance within a template, declare a ref in setup() and return it as usualCopy the code
<template>
  <div class="app">
    <h1 ref="hRef">The hook function ----123</h1>

    <Demo ref="dRef"></Demo>
  </div>
</template>

<script>
import Demo from './Demo.vue'
import { ref, provide, onMounted } from 'vue'
export default {
  components: {
    Demo
  },
  setup() {
    // an empty ref is created
    const hRef = ref(null)
    const dRef = ref(null)

    onMounted(() = > {
      console.log(hRef.value.innerHTML)
      console.log(dRef.value)
    })

    return {
      hRef,
      dRef
    }
  }
}
</script>

<style></style>

Copy the code

38 Comprehensive case todolist

<template>
  <section class="todoapp">
    <header class="header">
      <h1>todos</h1>
      <input
        class="new-todo"
        placeholder="What needs to be done?"
        autofocus
        v-model="todoName"
        @keyup.enter="addTodo"
      />
    </header>
    <! -- This section should be hidden by default and shown when there are todos -->
    <section class="main">
      <input
        id="toggle-all"
        class="toggle-all"
        type="checkbox"
        v-model="checkAll"
      />
      <label for="toggle-all">Mark all as complete</label>
      <ul class="todo-list">
        <li
          :class="{ completed: item.done, editing: item.id === currentId }"
          v-for="item in list"
          :key="item.id"
        >
          <div class="view">
            <input class="toggle" type="checkbox" v-model="item.done" />
            <label @dblclick="showTodo(item.id, item.name)">{{
              item.name
            }}</label>
            <button class="destroy" @click="delTodo(item.id)"></button>
          </div>
          <input
            class="edit"
            v-model="currentName"
            @keyup.esc="currentId = ''"
            @keyup.enter="editTodo(item)"
          />
        </li>
      </ul>
    </section>
    <! -- This footer should hidden by default and shown when there are todos -->
    <footer class="footer" v-if="list.length > 0">
      <! -- This should be `0 items left` by default -->
      <span class="todo-count"
        ><strong>{{ leftCount }}</strong> item left</span
      >
      <! -- Remove this if you don't implement routing -->
      <ul class="filters">
        <li>
          <a class="selected" href="# /">All</a>
        </li>
        <li>
          <a href="#/active">Active</a>
        </li>
        <li>
          <a href="#/completed">Completed</a>
        </li>
      </ul>
      <! -- Hidden if no completed items are left ↓ -->
      <button class="clear-completed" v-if="isShow" @click="clearTodo">
        Clear completed
      </button>
    </footer>
  </section>
</template>

<script>
import { reactive, toRefs, computed, watch } from 'vue'
export default {
  setup() {
    const state = reactive({
      todoName: ' '.// Record the id of the task to be modified
      currentId: ' '.// Record the name of the task to be modified
      currentName: ' '.// List of tasks that need to be completed
      list: JSON.parse(localStorage.getItem('todos') | | []})const delTodo = (id) = > {
      // console.log(' delete ', id)
      state.list = state.list.filter((item) = >item.id ! == id) }const addTodo = () = > {
      const todo = {
        id: Date.now(),
        name: state.todoName,
        done: false
      }
      state.list.unshift(todo)
      state.todoName = ' '
    }

    const showTodo = (id, name) = > {
      state.currentId = id
      state.currentName = name
      console.log(state.currentId)
      console.log(state.currentName)
    }

    const editTodo = (todo) = > {
      todo.name = state.currentName
      state.currentId = ' '
    }

    const clearTodo = () = > {
      state.list = state.list.filter((item) = >! item.done) }const computedData = reactive({
      leftCount: computed(() = > {
        return state.list.filter((item) = >! item.done).length }),isShow: computed(() = > {
        return state.list.some((item) = > item.done)
      }),
      checkAll: computed({
        get: () = > {
          return state.list.every((item) = > item.done)
        },
        set: (value) = > {
          state.list.forEach((item) = > (item.done = value))
        }
      })
    })

    watch(
      () = > state.list,
      (value) = > {
        localStorage.setItem('todos'.JSON.stringify(state.list))
      },
      {
        // Deep monitor
        deep: true})return{... toRefs(state), ... toRefs(computedData), delTodo, addTodo, showTodo, editTodo, clearTodo } } }</script>

Copy the code