Javascript

Vue学习笔记

本文主要是介绍Vue学习笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

前言

  • 注意事项:由于我打包的时候路径没写好,所以笔记上图片加载不出来
  • 所以笔记完整记录会放上来

ES6语法补充

let/var

JS中使用var来声明一个变量时, 变量的作用域主要是和函数的定义有关.针对于其他块定义来说是没有作用域的,比如if/for等,这在我们开发中往往会引起一些问题。

总之用let就好了,var淘汰了

const关键字

当我们修饰的标识符不会被再次赋值时, 就可以使用const来保证数据的安全性.

属性初始化简写和方法的简写

let name = "123"
//以前的写法
let people1 = {name:name}
//之后的写法
let people = {name}
fuc2:fuction(){
    
}
fuc1(){
    
}

Promise

Promise是异步编程的一种解决方案

三种状态

  • pending:等待状态,比如正在进行网络请求,或者定时器没有到时间。
  • fulfill:满足状态,当我们主动回调了resolve时,就处于该状态,并且会回调.then()
  • reject:拒绝状态,当我们主动回调了reject时,就处于该状态,并且会回调.catch()

函数

Promise.resovle():将数据包装成Promise对象,并且在内部回调resolve()函数

Promise.reject():将数据包装成Promise对象,并且在内部回调reject()函数

写法

  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('aaa')
    }, 1000)
  }).then(res => {
    // 1.自己处理10行代码
    console.log(res, '第一层的10行处理代码');

    // 2.对结果进行第一次处理
    return res + '111'
  }).then(res => {
    console.log(res, '第二层的10行处理代码');

    return Promise.resolve(res + '222')
  }).then(res => {
    return new Promise((resolve, reject) => {
  		resolve(res + '111')
       //reject('err')
     })
  }).then(res=>{
      
  })

ES6模块化开发

为什么模块化开发

为什么会出现模块化开发

​ 在网页开发的早期,js制作作为一种脚本语言,做一些简单的表单验证或动画实现等,那个时候代码还是很少的。客户端需要完成的事情越来越多,代码量也是与日俱增。为了应对代码量的剧增,我们通常会将代码组织在多个js文件中,进行维护。但是这种维护方式,依然不能避免一些灾难性的问题。例如:全局变量同名等问题

匿名函数可以解决全局变量,但是另外一个文件中不容易使用,因为flag是一个局部变量

export

导出变量

export let name = 5;
export let age = 5;
let name = 5;
export {name}

导出函数或类

export class person{
    int age;
}
export function test(){
    
}
class person{
    int age;
}
function test(){
    
}
export {test,person}

export default

某些情况下,一个模块中包含某个的功能,我们并不希望给这个功能命名,而且让导入者可以自己来命名

export default在同一个模块中,不允许同时存在多个

export default function(){
    
}
import fun from '路径'

import

首先,我们需要在HTML代码中引入两个js文件,并且类型需要设置为module

<script type = "module" src="文件路径"></script>

import指令用于导入模块中的内容,比如main.js的代码

import {name,age} from "./info.js"

如果我们希望某个模块中所有的信息都导入,一个个导入显然有些麻烦

import * as info from "./info.js"info.ages

Vue简介

编程范式声明式编程

Vue安装

方式一:直接CDN引入

  • 可以选择引入开发环境本办还是生产环境版本

    <!-- 开发环境版本,包含了有帮助的命令行警告 --><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- 生产环境版本,优化了尺寸和速度 --><script src="https://cdn.jsdelivr.net/npm/vue"></script>
    
  • 下载和引入

    https://vuejs.org/js/vue.jshttps://vuejs.org/js/vue.min.js
    
  • NUM

Vue基础语法

插值操作(Mustache语法)

基础语法

  • 用=={{}}==表示

  • 里面可以进行运算,一些简单的表达式

其他指令

  • v-once

    • 第一次显示什么值就是什么值,不会因为Vue数据的改变发生改变

    • 例子

      <!DOCTYPE html><html lang="en"><head></head><body>    <div id="app">        <div v-once>{{name}}</div>    </div></body><script src="vue.js"></script><script>    new Vue({        el: "#app",        data: {            name: "hello",            url: "<a href='http://www.baidu.com'>百度一下</a>"        }    })</script></html>
      
  • v-html

    • 将里面的值按照html解析出来

    • 例子

      <!DOCTYPE html><html lang="en"><head></head><body>    <div id="app">        <div v-html = "url"></div>    </div></body><script src="vue.js"></script><script>    new Vue({        el: "#app",        data: {            url: "<a href='http://www.baidu.com'>百度一下</a>"        }    })</script></html>
      

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dNSN2IoA-1621734333674)(图片\v-html测试图.png)]

  • v-text

    • v-text会把里面内容覆盖掉

    • 例子

      <!DOCTYPE html><html lang="en"><head></head><body>    <div id="app">        <div v-text="url">{{name}}</div>        <div>{{url}},{{name}}</div>    </div></body><script src="vue.js"></script><script>    new Vue({        el: "#app",        data: {            name: "hello",            url: "<a href='http://www.baidu.com'>百度一下</a>"        }    })</script></html>
      
  • v-pre

    • v-pre不会将{{}}转义成数据,原封不动显示出来

    • 例子

      <!DOCTYPE html><html lang="en"><head></head><body>    <div id="app">        <div v-pre>{{url}}</div>    </div></body><script src="vue.js"></script><script>    new Vue({        el: "#app",        data: {            url: "<a href='http://www.baidu.com'>百度一下</a>"        }    })</script></html>
      
  • v-cloak

    • 由于Vue在解析的时候,还没有将{{}}转化,可能会让用户看见

    • 在vue解析之前,div中有一个属性v-cloak,在vue解析之后,div中没有一个属性v-clcak

    • 例子

      <!DOCTYPE html><html lang="en"><head>    <style>        [v-cloak]{            display: none        }    </style></head><body>    <div id="app" v-cloak>    </div></body><script src="vue.js"></script><script>    new Vue({        el: "#app",        data: {                   }    })</script></html>
      

示例代码

<!DOCTYPE html><html lang="en"><head>    <style>        [v-cloak]{            display: none        }    </style></head><body>    <div id="app" v-cloak>        {{name}},        {{num1 + num2}}        <div v-once>{{name}}</div>        <div>{{url}}</div>        <div v-html="url"></div>        <div v-text="url">{{name}}</div>        <div>{{url}},{{name}}</div>        <div v-pre>{{url}}</div>    </div></body><script src="vue.js"></script><script>    new Vue({        el: "#app",        data: {            name: "hello",            num1: 3,            num2: 5,            url: "<a href='http://www.baidu.com'>百度一下</a>"        }    })</script></html>

绑定属性

v-bind指令

v-bind用于绑定一个或多个属性值,或者向另一个组件传递props值(这个学到组件时再介绍)

绑定class

方式一:对象语法

  • 直接通过{}绑定一个类

    <h2 :class="{'active': isActive}">Hello World</h2><h2 :class="{'active': isActive, 'line': isLine}">Hello World</h2><!--用法三:和普通的类同时存在,并不冲突注:如果isActive和isLine都为true,那么会有title/active/line三个类--><h2 class="title" :class="{'active': isActive, 'line': isLine}">Hello World</h2>
    
  • 如果绑定的过于复杂,可以放在一个methods或者computed中

    <h2 class="title" :class="classes">Hello World</h2><script>	new Vue({        methods:{            classes(){                return {'active': isActive, 'line': isLine}            }        }    })</script>
    

方式二:数组语法

  • 直接通过{}绑定一个类

    <h2 :class="['active', 'line']">Hello World</h2><h2 class="title" :class="['active', 'line']">Hello World</h2>
    
  • 如果过于复杂,可以放在一个methods或者computed中

    <h2 class="title" :class="classes">Hello World</h2><script>	new Vue({        methods:{            classes(){                return ['active', 'line']            }        }    })</script>
    
示例代码
<!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>Document</title>    <style>        .active {            color: red;            font-size: 50px;        }        .aaaa {            color: blueviolet;            font-size: 50px;        }    </style></head><body>    <div id="app">        <a v-bind:href="url">百度</a>        <a :href="url">百度</a>        <a :class="{active:isActive}" :href="url">百度</a>        <a :class="getClassesd" :href="url">百度</a>        <a :class="[classA]" :href="url">百度</a>        <a :class="['classA']" :href="url">百度</a>    </div></body><script src="vue.js"></script><script>    new Vue({        el: "#app",        data: {            url: "https://www.baidu.com",            isActive: false,            classA: "aaaa"        },        methods: {            getClassesd: function () {                return { active: this.isActive }            }        }    })</script></html>

绑定style

对象绑定

  • 对象的key是CSS属性名称

  • 对象的value是具体赋的值,值可以来自于data中的属性

    <body>    <div id="app">        <p :style="{color:currentColor}">你好</p>        <p :style="{color:'blue'}">你好</p>    </div></body><script src="vue.js"></script><script>    new Vue({        el: "#app",        data: {            currentColor: 'red'        }    })</script>
    

数组绑定

<body>    <div id="app">        <p :style="[styleObject,baseSize]">你好</p>        <p :style="{color:'blue'}">你好</p>    </div></body><script src="vue.js"></script><script>    new Vue({        el: "#app",        data: {            styleObject: {                color: 'red',            },            baseSize: { fontSize: '50px' }        }    })</script>

示例代码

<!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>Document</title>    <style>        .active {            color: red;        }    </style></head><body>    <div id="app">        <a v-bind:href="url">百度</a>        <a :href="url">百度</a>        <a :class="{active:isActive}" :href="url">百度</a>    </div></body><script src="vue.js"></script><script>    new Vue({        el: "#app",        data: {            url: "https://www.baidu.com",            isActive: false        },        method:{            getClasses(){                return {active:this.isActive}            }        }    })</script></html>

计算属性

  • 我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示

  • 每个计算属性都包含一个getter和一个setter。

    很多情况下,我们只提供getter方法,在某些情况下,你也可以提供一个setter方法(不常用)。

  • 计算属性有缓存,在没有改变值情况下,会保存在缓存

<!DOCTYPE html><html lang="en"><body>    <div id="app">        <p>{{fullName}}</p>        <p>{{tell}}</p>    </div></body><script src="vue.js"></script><script>    new Vue({        el: "#app",        data: {            first:"哈哈哈",            second:"你好"        },        computed:{            fullName(){                return this.first + " "+this.second;            },            tell(){                get(){                    return this.first + " "+this.second;                }                set(newValue){                   this.first = "123"                }            }        }    })</script></html>

事件监听

v-on:

  • 介绍:绑定事件监听器

  • v-on也有对应的语法糖:v-on:click可以写成@click

  • 注意事项:

    • 如果该方法不需要额外参数,那么方法后的()可以不添加

      如果方法本身中有一个或者多个参数,那么会默认将原生事件event参数传递进去

    • 如果需要同时传入某个参数,同时需要event时,可以通过$event传入事件

  • v-on修饰符

    • .stop:防止事件冒泡。等于调用 event.stopPropagation()

    • .prevent:阻止默认行为。等于调用 event.preventDefault()

    • .{keyCode | keyAlias}:只当事件是从特定键触发时才触发回调。

    • .native:监听组件根元素的原生事件

    • .once:只触发一次回调

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ae7MEdjR-1621734333678)(图片\v-on的表达式.png)]

条件判断

v-if、v-else-if、v-else

  • Vue的条件指令可以根据表达式的值在DOM中渲染或销毁元素或组件
  • v-if后面的条件为false时,对应的元素以及其子元素不会渲染。根本没有对应的标签出现在DOM中

v-show

  • v-show的用法和v-if非常相似,也用于决定一个元素是否渲染

两者对比

  • v-if当条件为false时,压根不会有对应的元素在DOM中。v-show当条件为false时,仅仅是将元素的display属性设置为none
  • 当需要在显示与隐藏之间切片很频繁时,使用v-show当只有一次切换时,通过使用v-if

遍历循环

v-for遍历数组

  • 在遍历的过程中不需要使用索引值: v-for=“movie in movies”
  • 需要拿到元素在数组中的索引值:v-for=(item, index) in items

v-for遍历对象

  • v-for可以用户遍历对象
  • 在遍历对象的过程中, 如果只是获取一个值, 那么获取到的是value
  • 获取key和value 格式: (value, key)
  • 获取key和value和index 格式: (value, key, index)

组件的key属性

这个其实和Vue的虚拟DOM的Diff算法有关系

  • 有一个数组**[‘A’,‘B’,‘C’,‘D’,‘E’]**我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的

    即把C更新成F,D更新成C,E更新成D,最后再插入E

  • 使用key来给每个节点做一个唯一标识

    Diff算法就可以正确的识别此节点

    找到正确的位置区插入新的节点。

  • key的作用主要是为了高效的更新虚拟DOM

注意事项:数组更新

因为Vue是响应式的,所以当数据发生变化时,Vue会自动检测数据变化,视图会发生对应的更新。

直接修改不会更新,需要采用下面方法

Vue中包含了一组观察数组编译的方法。

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

filters

filters: {    showPrice(price) {      return '¥' + price.toFixed(2)    }  }
<h2>总价格: {{totalPrice | showPrice}}</h2>

表单绑定

Vue中使用v-model指令来实现表单元素和数据的双向绑定

  • v-model其实是一个语法糖,它的背后本质上是包含两个操作

    • v-bind绑定一个value属性

    • v-on指令给当前元素绑定input事件

      <input type="text" v-model="message"><!--等同于--><input type="text" v-bind:value="message" v-on:input="message = $event.target.value">
      

v-model与redio

<div id="app">  <label for="male">    <input type="radio" id="male" value="男" v-model="sex">男  </label>  <label for="female">    <input type="radio" id="female" value="女" v-model="sex">女  </label>  <h2>您选择的性别是: {{sex}}</h2></div><script src="../js/vue.js"></script><script>  const app = new Vue({    el: '#app',    data: {      message: '你好啊',      sex: '女'    }  })</script>

v-model与checkbox

  • 单个勾选框
    • v-model即为布尔值
    • 此时input的value并不影响v-model的值
  • 多个复选框
    • 当是多个复选框时,因为可以选中多个,所以对应的data中属性是一个数组
    • 当选中某一个时,就会将input的value添加到数组中
<div id="app">  <label for="agree">-->    <input type="checkbox" id="agree" v-model="isAgree">同意协议  </label>      <input type="checkbox" value="篮球" v-model="hobbies">篮球  <input type="checkbox" value="足球" v-model="hobbies">足球  <input type="checkbox" value="乒乓球" v-model="hobbies">乒乓球  <input type="checkbox" value="羽毛球" v-model="hobbies">羽毛球</div><script src="../js/vue.js"></script><script>  const app = new Vue({    el: '#app',    data: {      message: '你好啊',      isAgree: false, // 单选框      hobbies: [], // 多选框,      originHobbies: ['篮球', '足球', '乒乓球', '羽毛球', '台球', '高尔夫球']    }  })</script>

v-model与select

  • 单选
    • v-model绑定的是一个值
    • 当我们选中option中的一个时,会将它对应的value赋值到mySelect中
  • 多选
    • v-model绑定的是一个数组
    • 当选中多个值时,就会将选中的option对应的value添加到数组mySelects中
<div id="app">  <!--1.选择一个-->  <select name="abc" v-model="fruit">    <option value="苹果">苹果</option>    <option value="香蕉">香蕉</option>    <option value="榴莲">榴莲</option>    <option value="葡萄">葡萄</option>  </select>  <h2>您选择的水果是: {{fruit}}</h2>  <!--2.选择多个-->  <select name="abc" v-model="fruits" multiple>    <option value="苹果">苹果</option>    <option value="香蕉">香蕉</option>    <option value="榴莲">榴莲</option>    <option value="葡萄">葡萄</option>  </select>  <h2>您选择的水果是: {{fruits}}</h2></div><script src="../js/vue.js"></script><script>  const app = new Vue({    el: '#app',    data: {      message: '你好啊',      fruit: '香蕉',      fruits: []    }  })</script>

Vue组件化

Vue组件化思想

组件化是Vue.js中的重要思想

  • 它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用。
  • 任何的应用都会被抽象成一颗组件树

组件化思想的应用

  • 有了组件化的思想,我们在之后的开发中就要充分的利用它。
  • 尽可能的将页面拆分成一个个小的、可复用的组件。
  • 这样让我们的代码更加方便组织和管理,并且扩展性也更强。

注册组件的基本步骤

  • 创建组件构造器

    • Vue.extend()

      • 调用Vue.extend()创建的是一个组件构造器。
      • 通常在创建组件构造器时,传入template代表我们自定义组件的模板。
      • 该模板就是在使用到组件的地方,要显示的HTML代码。
      • 事实上,这种写法在Vue2.x的文档中几乎已经看不到了,它会直接使用下面我们会讲到的语法糖,但是在很多资料还是会提到这种方式,而且这种方式是学习后面方式的基础。
    • 例子

      • 没有分离写法

        <script>const cpnC = Vue.extend({    template: `      <div>        <h2>我是标题</h2>        <p>我是内容, 哈哈哈哈</p>        <p>我是内容, 呵呵呵呵</p>      </div>`  })</script>
        
      • 分离写法

        <!--分离写法--><template id="cpn">   <div>      <h2>我是标题</h2>      <p>我是内容,呵呵呵</p>   </div></template><script>        const i = Vue.extend({            template: "#cpn"        })</script>
        
  • 注册组件

    • Vue.component()

      • 调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称。
      • 所以需要传递两个参数:1、注册组件的标签名 2、组件构造器
    • 例子

      • 全局注册

        <script>	Vue.component('cpn', cpnC)</script>
        
      • 局部注册

        <script>	const app = new Vue({    components: {      // cpn使用组件时的标签名      cpn: cpnC    }  })</script>
        
      • 语法糖

        <script>    Vue.component('cpn1', {    template: `      <div>        <h2>我是标题1</h2>        <p>我是内容, 哈哈哈哈</p>      </div>    `  })</script>
        
      • 分离写法

        • template

          <template id="cpn">   <div>      <h2>我是标题</h2>      <p>我是内容,呵呵呵</p>   </div></template><script>  Vue.component('cpn', {    template: '#cpn'  })</script>
          
        • script写法

          <script type="text/x-template" id="cpn"><div>  <h2>我是标题</h2> <p>我是内容,哈哈哈</p></div></script><script>  Vue.component('cpn', {    template: '#cpn'  })</script>
          
  • 使用组件

    • 组件必须挂载在某个Vue实例下,否则它不会生效。

    • 例子

      <cpn></cpn>
      

组件数据处理

Vue组件应该有自己保存数据的地方

组件自己的数据

  • 组件对象也有一个data属性(也可以有methods等属性,下面我们有用到)
  • 只是==这个data属性必须是一个函数==
    • 首先,如果不是一个函数,Vue直接就会报错。
    • 其次,原因是在于Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。
  • 而且这个函数返回一个对象,对象内部保存着数据

父子组件的通信

在开发中,往往一些数据确实需要从上层传递到下层

  • 比如在一个页面中,我们从服务器请求到了很多的数据。
  • 其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示。
  • 这个时候,并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)

父级向子级传递

props基本用法

  • 可以类型限制、

    String、Number、Boolean、Array、Object、Date、Function、Symbol

    当我们有自定义构造函数时,验证也支持自定义的类型

    cmessage: String
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ne3ZsQgX-1621734333682)(图片\数据类型.png)]

  • 提供一些默认值, 以及必传值

    cmessage: {        type: String,        default: 'aaaaaaaa',        required: true      },
    
  • 如果是一个对象,数组需要定义为函数

    cmovies: {        type: Array,        default() {          return []        }      }
    
  • 在子组件上绑定号数据

    <div id="app">  <!--<cpn v-bind:cmovies="movies"></cpn>-->  <!--<cpn cmovies="movies" cmessage="message"></cpn>-->  <cpn :cmessage="message" :cmovies="movies"></cpn></div>
    

完整代码

<div id="app">  <!--<cpn v-bind:cmovies="movies"></cpn>-->  <!--<cpn cmovies="movies" cmessage="message"></cpn>-->  <cpn :cmessage="message" :cmovies="movies"></cpn></div><template id="cpn">  <div>    <ul>      <li v-for="item in cmovies">{{item}}</li>    </ul>    <h2>{{cmessage}}</h2>  </div></template><script src="../js/vue.js"></script><script>  // 父传子: props  const cpn = {    template: '#cpn',    // props: ['cmovies', 'cmessage'],    props: {      // 1.类型限制      // cmovies: Array,      // cmessage: String,      // 2.提供一些默认值, 以及必传值      cmessage: {        type: String,        default: 'aaaaaaaa',        required: true      },      // 类型是对象或者数组时, 默认值必须是一个函数      cmovies: {        type: Array,        default() {          return []        }      }    },    data() {      return {}    },    methods: {    }  }  const app = new Vue({    el: '#app',    data: {      message: '你好啊',      movies: ['海王', '海贼王', '海尔兄弟']    },    components: {      cpn    }  })</script>

子级向父级传递

自定义事件

  • 当子组件需要向父组件传递数据时,就要用到自定义事件了。
  • v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件

自定义事件的流程

  • 在子组件中,通过$emit()来触发事件
  • 在父组件中,通过v-on来监听子组件事件
<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <title>Title</title></head><body><!--父组件模板--><div id="app">  <cpn @item-click="cpnClick"></cpn></div><!--子组件模板--><template id="cpn">  <div>    <button v-for="item in categories"            @click="btnClick(item)">      {{item.name}}    </button>  </div></template><script src="../js/vue.js"></script><script>  // 1.子组件  const cpn = {    template: '#cpn',    data() {      return {        categories: [          {id: 'aaa', name: '热门推荐'},          {id: 'bbb', name: '手机数码'},          {id: 'ccc', name: '家用家电'},          {id: 'ddd', name: '电脑办公'},        ]      }    },    methods: {      btnClick(item) {        // 发射事件: 自定义事件        this.$emit('item-click', item)      }    }  }  // 2.父组件  const app = new Vue({    el: '#app',    data: {      message: '你好啊'    },    components: {      cpn    },    methods: {      cpnClick(item) {        console.log('cpnClick', item);      }    }  })</script></body></html>

webpack

概念

模块化

在ES6之前,我们要想进行模块化开发,就必须借助于其他的工具,让我们可以进行模块化开发。并且在通过模块化开发完成了项目后,还需要处理模块间的各种依赖,并且将其进行整合打包。而webpack其中一个核心就是让我们可能进行模块化开发,并且会帮助我们处理模块间的依赖关系。而且不仅仅是JavaScript文件,我们的CSS、图片、json文件等等在webpack中都可以被当做模块来使用(在后续我们会看到)。这就是webpack中模块化的概念。

打包

就是将webpack中的各种资源模块进行打包合并成一个或多个包(Bundle)。并且在打包的过程中,还可以对资源进行处理,比如压缩图片,将scss转成css,将ES6语法转成ES5语法,将TypeScript转成JavaScript等等操作。

grunt/gulp和webpack有什么不同

  • grunt/gulp更加强调的是前端流程的自动化,模块化不是它的核心。
  • webpack更加强调模块化开发管理,而文件压缩合并、预处理等功能,是他附带的功能。

安装

  • 安装webpack首先需要安装Node.js,Node.js自带了软件包管理工具npm

  • 查看自己的node版本

    node -v
    
  • 全局安装webpack(这里我先指定版本号3.6.0,因为vue cli2依赖该版本)

    npm install webpack@3.6.0 -g
    
  • 局部安装webpack

    #cd ......npm install webpack@3.6.0 -g --save-dev
    
  • 在终端直接执行webpack命令,使用的全局安装的webpack当在package.json中定义了scripts时,其中包含了webpack命令,那么使用的是局部webpack

文件和文件夹解析

  • dist文件夹:用于存放之后打包的文件
  • src文件夹:用于存放我们写的源文件
  • main.js:项目的入口文件。具体内容查看下面详情。
  • mathUtils.js:定义了一些数学工具函数,可以在其他地方引用,并且使用。具体内容查看下面的详情。
  • index.html:浏览器打开展示的首页html
  • package.json:通过npm init生成的,npm包管理的文件(暂时没有用上,后面才会用上)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m5KxXZMJ-1621734333685)(\图片\webpack.png)]

打包

打包命令

webpack ./src/main.js ./dist/bundle.js

处理完所有模块之间的关系后,将多个js打包到一个js文件中,引入时就变得非常方便了

入口和出口

​ 每次书写还是比较麻烦,故需要写一个webpack.config.js

const path = require('path')module.exports = {  entry: './src/main.js',  output: {    path: path.resolve(__dirname, 'dist'),    filename: 'bundle.js',      //publicPath: 'dist/'//输出到特定文件里面  },}

局部安装webpack

  • 第一步,项目中需要安装自己局部的webpack这里我们让局部安装webpack3.6.0
    Vue CLI3中已经升级到webpack4,但是它将配置文件隐藏了起来,所以查看起来不是很方便
  • 第二步,通过node_modules/.bin/webpack启动webpack打包

package.json中定义启动

  • package.json中的scripts的脚本在执行时,会按照一定的顺序寻找命令对应的位置。首先,会寻找本地的node_modules/.bin路径中对应的命令。如果没有找到,会去全局的环境变量中寻找。

    {  "name": "meetwebpack",  "version": "1.0.0",  "description": "",  "main": "index.js",  "scripts": {    "test": "echo \"Error: no test specified\" && exit 1",    "build": "webpack"  },  "author": "",  "license": "ISC",  "devDependencies": {    "webpack": "^3.6.0"  }}
    

loader

在开发中我们不仅仅有基本的js代码处理,我们也需要加载css、图片,也包括一些高级的将ES6转成ES5代码,将TypeScript转成ES5代码,将scss、less转成css,将.jsx、.vue文件转成js文件等等,这时候需要loader

loader使用过程:

  • 步骤一:通过npm安装需要使用的loader

  • 步骤二:在webpack.config.js中的modules关键字下进行配置

    const path = require('path')module.exports = {  entry: './src/main.js',  output: {    path: path.resolve(__dirname, 'dist'),    filename: 'bundle.js'  },  module: {    rules: [      {        test: /\.css$/,        // css-loader只负责将css文件进行加载        // style-loader负责将样式添加到DOM中        // 使用多个loader时, 是从右向左        use: [ 'style-loader', 'css-loader' ]      }    ]  }}
    

css文件处理 – style-loader

我们来安装style-loader

npm install --save-dev style-loader

这次因为webpack在读取使用的loader的过程中,是按照从右向左的顺序读取的

module: {    rules: [      {        test: /\.css$/,        // css-loader只负责将css文件进行加载        // style-loader负责将样式添加到DOM中        // 使用多个loader时, 是从右向左        use: [ 'style-loader', 'css-loader' ]      }    ]  }

less文件处理- less-loader

npm install --save-dev less-loader less
{   	test: /\.less$/,   	use: [{    	loader: "style-loader", // creates style nodes from JS strings   	}, {     	loader: "css-loader" // translates CSS into CommonJS    }, {        loader: "less-loader", // compiles Less to CSS	}]}

图片文件处理 – url-loader

npm install --save-dev url-loader
{        test: /\.(png|jpg|gif|jpeg)$/,        use: [          {            loader: 'url-loader',            options: {              // 当加载的图片, 小于limit时, 会将图片编译成base64字符串形式.              // 当加载的图片, 大于limit时, 需要使用file-loader模块进行加载.              limit: 13000,                //设置位置,名字和Hash值              name: 'img/[name].[hash:8].[ext]'            },          }        ]      }

图片文件处理 – file-loader

npm install --save-dev file-loader

ES6语法处理

npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
{        test: /\.js$/,        // exclude: 排除        // include: 包含        exclude: /(node_modules|bower_components)/,        use: {          loader: 'babel-loader',          options: {            presets: ['es2015']          }        }      }

引入vue.js

npm install vue --save

在main.js上

// 5.使用Vue进行开发import Vue from 'vue'// import App from './vue/app'import App from './vue/App.vue'new Vue({  el: '#app',  template: '<App/>',  components: {    App  }})

在index.html

<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <title>Title</title></head><body><div id="app"></div><script src="./dist/bundle.js"></script></body></html>

在webpack.config.js

  resolve: {    // alias: 别名    extensions: ['.js', '.css', '.vue'],    alias: {      'vue$': 'vue/dist/vue.esm.js'    }  }

.vue文件封装处理

演化

自定义了组件,也必须修改index.html来使用组件。为了避免修改----------------->定义template
在前面的Vue实例中,我们定义了el属性,用于和index.html中的#app进行绑定,让Vue实例之后可以管理它其中的内容这里,我们可以将div元素中的{{message}}内容删掉,只保留一个基本的id为div的元素我们定义一个template属性。在我们之前的学习中,我们知道el用于指定Vue要管理的DOM,可以帮助解析其中的指令、事件监听等等。而如果Vue实例中同时指定了template,那么template模板的内容会替换掉挂载的对应el的模板。这样做之后我们就不需要在以后的开发中再次操作index.html,只需要在template中写入对应的标签即可

书写template模块非常麻烦怎么办呢?

没有关系,稍后我们会将template模板中的内容进行抽离。
会分成三部分书写:template、script、style,结构变得非常清晰。

安装vue-loader和vue-template-compiler来处理新文件

npm install vue-loader vue-template-compiler --save-dev

修改webpack.config.js的配置文件

      {        test: /\.vue$/,        use: ['vue-loader']      }

plugin

plugin是插件的意思,通常是用于对某个现有的架构进行扩展。

webpack中的插件,就是对webpack现有功能的各种扩展,比如打包优化,文件压缩等等。

loader和plugin区别:

  • loader主要用于转换某些类型的模块,它是一个转换器。
  • plugin是插件,它是对webpack本身的扩展,是一个扩展器。

plugin的使用过程

  • 步骤一:通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装)
  • 步骤二:在webpack.config.js中的plugins中配置插件。

添加版权的Plugin

该插件名字叫BannerPlugin,属于webpack自带的插件。

修改webpack.config.js

plugins: [      new webpack.BannerPlugin('最终版权归aaa所有')]

打包html的plugin

目前,我们的index.html文件是存放在项目的根目录下的。我们知道,在真实发布项目时,发布的是dist文件夹中的内容,但是dist文件夹中如果没有index.html文件,那么打包的js等文件也就没有意义了。所以,我们需要将index.html文件打包到dist文件夹中,这个时候就可以使用HtmlWebpackPlugin插件

HtmlWebpackPlugin插件可以为我们做这些事情:自动生成一个index.html文件(可以指定模板来生成)将打包的js文件,自动通过script标签插入到body中

使用插件,修改webpack.config.js文件中plugins部分的内容如下:这里的template表示根据什么模板来生成index.html另外,我们需要删除之前在output中添加的publicPath属性,否则插入的script标签中的src可能会有问题

npm install html-webpack-plugin --save-dev
plugins: [      new webpack.BannerPlugin('最终版权归aaa所有'),    new HtmlWebpackPlugin({        template: 'index.html'      }),]

js压缩的Plugin

npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
plugins: [      new webpack.BannerPlugin('最终版权归aaa所有'),    new HtmlWebpackPlugin({        template: 'index.html'      }),    new UglifyjsWebpackPlugin()]

搭建本地服务器

npm install --save-dev webpack-dev-server@2.9.1

devserver也是作为webpack中的一个选项,选项本身可以设置如下属性:

  • contentBase:为哪一个文件夹提供本地服务,默认是根文件夹,我们这里要填写./dist
  • port:端口号
  • inline:页面实时刷新
  • historyApiFallback:在SPA页面中,依赖HTML5的history模式
  devServer: {    contentBase: './dist',    inline: true  }
"scripts": {    "dev": "webpack-dev-server --open"  },

配置分离

npm install webpack-merge -D

package.json

"scripts": {    "test": "echo \"Error: no test specified\" && exit 1",    "build": "webpack --config ./build/prod.config.js",    "dev": "webpack-dev-server --open --config ./build/dev.config.js"  },

dev.config.js

const webpackMerge = require('webpack-merge')const baseConfig = require('./base.config')module.exports = webpackMerge(baseConfig, {  devServer: {    contentBase: './dist',    inline: true  }})

base.config.js

const path = require('path')const webpack = require('webpack')const HtmlWebpackPlugin = require('html-webpack-plugin')const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')module.exports = {  entry: './src/main.js',  output: {    path: path.resolve(__dirname, '../dist'),    filename: 'bundle.js',    // publicPath: 'dist/'  },  module: {    rules: [      {        test: /\.css$/,        // css-loader只负责将css文件进行加载        // style-loader负责将样式添加到DOM中        // 使用多个loader时, 是从右向左        use: [ 'style-loader', 'css-loader' ]      },      {        test: /\.less$/,        use: [{          loader: "style-loader", // creates style nodes from JS strings        }, {          loader: "css-loader" // translates CSS into CommonJS        }, {          loader: "less-loader", // compiles Less to CSS        }]      },      {        test: /\.(png|jpg|gif|jpeg)$/,        use: [          {            loader: 'url-loader',            options: {              // 当加载的图片, 小于limit时, 会将图片编译成base64字符串形式.              // 当加载的图片, 大于limit时, 需要使用file-loader模块进行加载.              limit: 13000,              name: 'img/[name].[hash:8].[ext]'            },          }        ]      },      {        test: /\.js$/,        // exclude: 排除        // include: 包含        exclude: /(node_modules|bower_components)/,        use: {          loader: 'babel-loader',          options: {            presets: ['es2015']          }        }      },      {        test: /\.vue$/,        use: ['vue-loader']      }    ]  },  resolve: {    // alias: 别名    extensions: ['.js', '.css', '.vue'],    alias: {      'vue$': 'vue/dist/vue.esm.js'    }  },  plugins: [    new webpack.BannerPlugin('最终版权归aaa所有'),    new HtmlWebpackPlugin({      template: 'index.html'    })  ]}

Vue CLI

#cnpm安装#由于国内直接使用 npm 的官方镜像是非常慢的,这里推荐使用淘宝 NPM 镜像。#你可以使用淘宝定制的 cnpm (gzip 压缩支持) 命令行工具代替默认的 npm:npm install -g cnpm --registry=https://registry.npm.taobao.org#这样就可以使用 cnpm 命令来安装模块了:#cnpm install [name]

安装Vue脚手架

npm install -g @vue/cli#上面安装的是Vue CLI3的版本,如果需要想按照Vue CLI2的方式初始化项目时不可以的npm install -g @vue/cli-init

初始化项目

Vue CLI2初始化项目

#Vue CLI2初始化项目vue init webpack my-project

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Io52cpko-1621734333687)(图片\创建详解.png)]

Vue CLI3初始化项目

#Vue CLI3初始化项目vue create my-project

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zNlTpPTl-1621734333689)(图片\CLI3.png)]

目录结构详解

Vue CLI 2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RBEv6xZP-1621734333690)(图片\vue目录结构.png)]

Vue CLI 3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-32MvGiiR-1621734333691)(图片\CLI3目录结构.png)]

CLI3配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QB6cyYSh-1621734333692)(图片\CLI3配置.png)]

vue.config.js 是一个可选的配置文件,如果项目的 (和 package.json 同级的) 根目录中存在这个文件,那么它会被 @vue/cli-service 自动加载。你也可以使用 package.json 中的 vue 字段,但是注意这种写法需要你严格遵照 JSON 的格式来写。

这个文件应该导出一个包含了选项的对象:

// vue.config.js/** * @type {import('@vue/cli-service').ProjectOptions} */module.exports = {  // 选项...}

Runtime-Compiler和Runtime-only

  • 如果在之后的开发中,你依然使用template,就需要选择Runtime-Compiler(最主要的入口里面还是使用template)
  • 如果你之后的开发中,使用的是.vue文件夹开发,那么可以选择Runtime-only

Runtime-Compiler:

new Vue({  el: '#app',  router: router,  template: '<router-view></router-view>'})

Runtime-only:

new Vue({  el: '#app',  router: router,  render: h => h('router-view')})

运行过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZAZ60x4B-1621734333693)(图片\vue运行过程.png)]

render函数

new Vue({    el:"#app",    render:(createElement)=>{//        return createElement('标签',"相关数据对象(可以不传)",["内容数组"]),        return createElement('div',{class:'box'},["create"])        return createElement('div',{class:'box'},["create",createElement('h2',["标题"])])    }})
const cpn = Vue.component('cpn',{    template:"<div></div>",    data(){        return{                    }    }})new Vue({    el:"#app",    render:(createElement)=>createElement(cpn)})

运行详情

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-70xP2H4y-1621734333694)(图片\vueBuild.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VRaixjPv-1621734333695)(图片\vueDev.png)]

vue-router

介绍

后端路由阶段

早期的网站开发整个HTML页面是由服务器来渲染的.

一个页面有自己对应的网址, 也就是URL.URL会发送到服务器, 服务器会通过正则对该URL进行匹配, 并且最后交给一个Controller进行处理.Controller进行各种处理, 最终生成HTML或者数据, 返回给前端.这就完成了一个IO操作.

当我们页面中需要请求不同的路径内容时, 交给服务器来进行处理, 服务器渲染好整个页面, 并且将页面返回给客户顿.这种情况下渲染好的页面, 不需要单独加载任何的js和css, 可以直接交给浏览器展示, 这样也有利于SEO的优化.

缺点:

  • 一种情况是整个页面的模块由后端人员来编写和维护的.
  • 另一种情况是前端开发人员如果要开发页面, 需要通过PHP和Java等语言来编写页面代码.
  • 而且通常情况下HTML代码和数据以及对应的逻辑会混在一起, 编写和维护都是非常糟糕的事情.

前端路由阶段

前后端分离阶段:随着Ajax的出现, 有了前后端分离的开发模式.后端只提供API来返回数据, 前端通过Ajax获取数据, 并且可以通过JavaScript将数据渲染到页面中.这样做最大的优点就是前后端责任的清晰, 后端专注于数据上, 前端专注于交互和可视化上.并且当移动端(iOS/Android)出现后, 后端不需要进行任何处理, 依然使用之前的一套API即可.

单页面富应用阶段:
其实SPA最主要的特点就是在前后端分离的基础上加了一层前端路由.也就是前端来维护一套路由规则.

改变路径的方式

URL的hash

URL的hash也就是锚点(#), 本质上是改变window.location的href属性.我们可以通过直接赋值location.hash来改变href, 但是页面不发生刷新

HTML5的history

history接口是HTML5新增的, 它有五种模式改变URL而不刷新页面.

  • history.pushState()
  • history.replaceState()
  • history.go()
  • history.back()
  • history.forward()

安装和使用

安装

安装vue-router

npm install vue-router --save

在模块化工程中使用它(因为是一个插件, 所以可以通过Vue.use()来安装路由功能)

router文件夹的index.js下

// 配置路由相关的信息import VueRouter from 'vue-router'import Vue from 'vue'// 1.通过Vue.use(插件), 安装插件Vue.use(VueRouter)// 2.创建VueRouter对象const routes = []const router = new VueRouter({  // 配置路由和组件之间的应用关系  routes,})// 3.将router对象传入到Vue实例export default router

main.js挂载

import Vue from 'vue'import App from './App'import router from './router'Vue.config.productionTip = falsenew Vue({  el: '#app',  router,//挂载  render: h => h(App)})

使用

创建路由组件

<template>  <div>    <h2>我是首页</h2>    <p>我是首页内容, 哈哈哈</p>  </div></template><script>  export default {    name: "Home"  }</script><style scoped></style>

配置组件和路径的映射关系

const routes = [  {    path: '',    // redirect重定向    redirect: '/home'  },  {    path: '/home',    component: Home  },  {    path: '/about',    component: About  }]

使用路由

: 该标签是一个vue-router中已经内置的组件, 它会被渲染成一个标签.
: 该标签会根据当前的路径, 动态渲染出不同的组件.
网页的其他内容, 比如顶部的标题/导航, 或者底部的一些版权信息等会和处于同一个等级.
在路由切换时, 切换的是挂载的组件, 其他内容不会发生改变.

路由的懒加载

当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了

路由懒加载

  • 路由懒加载的主要作用就是将路由对应的组件打包成一个个的js代码块.
  • 只有在这个路由被访问到的时候, 才加载对应的组件
const Home = () => import('../components/Home')const HomeNews = () => import('../components/HomeNews')const HomeMessage = () => import('../components/HomeMessage')const routes = [  {    path: '/home',    component: Home,  },]const router = new VueRouter({  // 配置路由和组件之间的应用关系  routes,  mode: 'history',  linkActiveClass: 'active'})

认识嵌套路由

一个路径映射一个组件, 访问这个路径也会分别渲染其他个组件.

嵌套路由也可以配置默认的路径

<template>  <div>    <ul>      <li>消息1</li>    </ul>  </div></template><script>  export default {    name: "HomeNews"  }</script><style scoped></style>
<template>  <div>    <h2>我是首页</h2>    <p>我是首页内容, 哈哈哈</p>    <router-link to="/home/message">消息</router-link>    <router-view></router-view>    <h2>{{message}}</h2>  </div></template><script>  export default {    name: "Home",    data() {      return {        message: '你好啊',        path: '/home/news'      }    }  }</script><style scoped></style>
import VueRouter from 'vue-router'import Vue from 'vue'const HomeMessage = () => import('../components/HomeMessage')const routes = [  {    path: '/home',    component: Home,    meta: {      title: '首页'    },    children: [       {         path: '',         redirect: 'news'       },      {        path: 'news',        component: HomeNews      },      {        path: 'message',        component: HomeMessage      }    ]  }]const router = new VueRouter({  // 配置路由和组件之间的应用关系  routes,  mode: 'history',  linkActiveClass: 'active'})export default router

传递参数的方式

params的类型:

  • 配置路由格式: /router/:id
  • 传递的方式: 在path后面跟上对应的值
  • 传递后形成的路径: /router/123, /router/abc
<router-link :to="'/user/'+userId">用户</router-link>
userClick() {      this.$router.push('/user/' + this.userId)    },
<h2>{{$route.params.id}}</h2>

query的类型

  • 配置路由格式: /router, 也就是普通配置
  • 传递的方式: 对象中使用query的key作为传递方式
  • 传递后形成的路径: /router?id=123, /router?id=abc
<router-link :to="{path: '/profile', query: {name: 'why', age: 18, height: 1.88}}">
profileClick() {      this.$router.push({        path: '/profile',        query: {          name: 'kobe',          age: 19,          height: 1.87        }      })    }
<h2>{{$route.query.name}}</h2>    <h2>{{$route.query.age}}</h2>    <h2>{{$route.query.height}}</h2>

$route和$router区别

  • $router为VueRouter实例,想要导航到不同URL,则使用$router.push方法
  • $route为当前router跳转对象里面可以获取name、path、query、params等

导航守卫

vue-router提供的导航守卫主要用来监听监听路由的进入和离开的

vue-router提供了beforeEach和afterEach的钩子函数, 它们会在路由即将改变前和改变后触发

导航钩子的三个参数解析:

参数意思
to即将要进入的目标的路由对象.
from当前导航即将要离开的路由对象.
next调用该方法后, 才能进入下一个钩子(对于beforeEach)

详细说明

keep-alive遇见vue-router

keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。

它们有两个非常重要的属性:

  • include - 字符串或正则表达,只有匹配的组件会被缓存
  • exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存
  • router-view 也是一个组件,如果直接被包在 keep-alive 里面,所有路径匹配到的视图组件都会被缓存
	<keep-alive exclude="Profile,User">      <router-view/>    </keep-alive>

细节

router-link

属性意义
to用于指定跳转的路径
tagtag可以指定之后渲染成什么组件, 比如上面的代码会被渲染成一个
  • 元素, 而不是
replacereplace不会留下history记录, 所以指定replace的情况下, 后退键返回不能返回到上一个页面中
active-class当对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class, 设置active-class可以修改默认的名称.可以在路由上修改活跃class名

路由代码跳转

export default {  name: 'App',  methods: {    homeClick() {      // 通过代码的方式修改路由 vue-router      // push => pushState      // this.$router.push('/home')      this.$router.replace('/home')      console.log('homeClick');    },    aboutClick() {      // this.$router.push('/about')      this.$router.replace('/about')      console.log('aboutClick');    }  }}

动态路由

const routes = [  {    path: '/user/:id',    component: About  }]
<div>    {{$route.params.id}}</div>

Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式

状态信息,我们都可以放在统一的地方,对它进行保存和管理,而且它们还是响应式的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Z8PMI3o-1621734333700)(图片\vuex.png)]

注册store

import Vue from 'vue'import App from './App'import store from './store'Vue.config.productionTip = falsenew Vue({  el: '#app',  store,  render: h => h(App)})
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)const store = new Vuex.Store({  state: {},  mutations: {},  actions: {},  getters: {},  modules: {}})

在其他Vue组件中,我们就可以通过this.$store的方式,获取到这个store对象了

State单一状态树

Vuex也使用了单一状态树来管理应用层级的全部状态。单一状态树能够让我们最直接的方式找到某个状态的片段,而且在之后的维护和调试过程中,也可以非常方便的管理和维护。

Getters

基本使用

有时候,我们需要从store中获取一些state变异后的状态,比如下面的Store。就是需要进行一定运算

import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)const store = new Vuex.Store({  state: {},  mutations: {},  actions: {},  getters: {    powerCounter(state) {      return state.counter * state.counter    },  },  modules: {}})

传参数

自带两个参数

  • state:当前的state
  • getters:当前的getters
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)const store = new Vuex.Store({  state: {},  mutations: {},  actions: {},  getters: {    powerCounter(state,getters) {      return state.counter * state.counter    },  },  modules: {}})

getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数

getters: {    moreAgeStu(state) {      // return function (age) {      //   return state.students.filter(s => s.age > age)      // }      return age => {        return state.students.filter(s => s.age > age)      }    }  },

Mutation

基本使用

Vuex的store状态的更新唯一方式:提交Mutation

new Vuex.Store({mutations: {	decrement(state) {      state.counter--    },}})

通过mutation更新

subtraction() {        this.$store.commit('decrement')    // 2.特殊的提交封装        this.$store.commit({          type: 'incrementCount',          count        })      },

传参数

在通过mutation更新数据的时候, 有可能我们希望携带一些额外的参数。参数被称为是mutation的载荷(Payload)

参数只有一个的时候,可以直接写。如果多个参数,传入对象

incrementCount(state, payload) {      // console.log(count);      state.counter += payload.count    },

Mutation响应规则

Vuex的store中的state是响应式的, 当state中的数据发生改变时, Vue组件会自动更新.

这就要求我们必须遵守一些Vuex对应的规则:

提前在store中初始化好所需的属性.

当给state中的对象添加新属性时, 使用下面的方式:

  • 方式一: 使用Vue.set(obj, ‘newProp’, 123)

    Vue.set(state.info, 'address', '洛杉矶')
    
  • 方式二: 用新对象给旧对象重新赋值

    state.info={...state.info,address = "洛杉矶"}
    

Mutation常量类型

export const SOME_MUTATION = 'SOME_MUTATION'
// store.jsimport Vuex from 'vuex'import { SOME_MUTATION } from './mutation-types'const store = new Vuex.Store({  state: { ... },  mutations: {    // 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名    [SOME_MUTATION] (state) {      // mutate state    }  }})

Mutation 必须是同步函数

Vuex要求我们Mutation中的方法必须是同步方法

  • 主要的原因是当我们使用devtools时, 可以devtools可以帮助我们捕捉mutation的快照.
  • 但是如果是异步操作, 那么devtools将不能很好的追踪这个操作什么时候会被完成

Action

处理异步操作

Vue组件中, 如果我们调用action中的方法, 那么就需要使用dispatch

同样的, 也是支持传递payload

你需要明白 store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch仍旧返回 Promise

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用context.commit 提交一个 mutation,或者通过 context.statecontext.getters 来获取 state 和 getters

const store = new Vuex.Store({  state: {    count: 0  },  mutations: {    increment (state) {      state.count++    }  },  actions: {    increment (context) {      context.commit('increment')    }  }})

Module

Vuex 允许我们将 store 分割成模块(module)

const moduleA = {  state: () => ({ ... }),  mutations: { ... },  actions: { ... },  getters: { ... }}const moduleB = {  state: () => ({ ... }),  mutations: { ... },  actions: { ... }}const store = new Vuex.Store({  modules: {    a: moduleA,    b: moduleB  }})store.state.a // -> moduleA 的状态store.state.b // -> moduleB 的状态

模块的局部状态

对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象

const moduleA = {  state: () => ({    count: 0  }),  mutations: {    increment (state) {      // 这里的 `state` 对象是模块的局部状态      state.count++    }  },  getters: {    doubleCount (state) {      return state.count * 2    }  }}

同样,对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState

const moduleA = {  // ...  actions: {    incrementIfOddOnRootSum ({ state, commit, rootState }) {      if ((state.count + rootState.count) % 2 === 1) {        commit('increment')      }    }  }}

对于模块内部的 getter,根节点状态会作为第三个参数暴露出来

const moduleA = {  // ...  getters: {    sumWithRootCount (state, getters, rootState) {      return state.count + rootState.count    }  }}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xV0BGpFC-1621734333703)(图片\vuexFile.png)]

axios

发送并发请求

有时候, 我们可能需求同时发送两个请求

  • 使用axios.all, 可以放入多个请求的数组.
  • axios.all([]) 返回的结果是一个数组,使用 axios.spread 可将数组 [res1,res2] 展开为 res1, res2

全局配置

axios.defaults.baseURL = ‘123.207.32.32:8000’;axios.defaults.headers.post[‘Content-Type’] = ‘application/x-www-form-urlencoded’;

常见的配置选项

参数意思
请求地址url: ‘/user’
请求类型method: ‘get’
请根路径baseURL: ‘http://www.mt.com/api’
请求前的数据处理transformRequest:[function(data){}]
请求后的数据处理transformResponse: [function(data){}]
自定义的请求头headers:{‘x-Requested-With’:‘XMLHttpRequest’}
URL查询对象params:{ id: 12 }
查询对象序列化函数paramsSerializer: function(params){ }
request bodydata: { key: ‘aa’},
超时设置timeout: 1000
跨域是否带TokenwithCredentials: false
自定义请求处理adapter: function(resolve, reject, config){}
身份验证信息auth: { uname: ‘’, pwd: ‘12’}
响应的数据格式responseType: ‘json’(json / blob /document /arraybuffer / text / stream)

拦截器

const instance = axios.create({      baseURL: 'http://123.207.32.32:8000',      timeout: 5000    })instance.interceptors.response.use(res => {      return res.data    })instance.interceptors.request.use(res => {      return res.data    })

封装

// ES6 Promise的封装export function request(options) {  return new Promise((resolve, reject) => {    // 1.创建axios的实例对象    const instance = axios.create({      baseURL: 'http://123.207.32.32:8000',      timeout: 5000    })    // 过滤器(拦截器)    instance.interceptors.response.use(res => {      return res.data    })    // 通过实例发送网络请求    instance(options)        .then(res => {          resolve(res)        }).catch(err => {          reject(err)    })  })}
ES5封装方式export function request(options, success, failure) {  // 1.创建axios的实例对象  const instance = axios.create({    baseURL: 'http://123.207.32.32:8000',    timeout: 5000  })  // 过滤器(拦截器)  instance.interceptors.response.use(res => {    return res.data  })  // 通过实例发送网络请求  instance(options)      .then(res => {        success(res)      }).catch(err => {        failure(err)      })}

注意

输入框依旧保留原来数据

  • 问题描述
    • 如果我们在有输入内容的情况下,切换了类型,我们会发现文字依然显示之前的输入的内容。
  • 问题解答
    • 这是因为Vue在进行DOM渲染时,出于性能考虑,会尽可能的复用已经存在的元素,而不是重新创建新的元素。
  • 解决方案
    • 对应的input添加key,并且我们需要保证key的不同

父组件和子组件

父子组件错误用法:以子标签的形式在Vue实例中使用

因为当子组件注册到父组件的components时,Vue会编译好父组件的模块

该模板的内容已经决定了父组件将要渲染的HTML(相当于父组件中已经有了子组件中的内容了)

是只能在父组件中被识别的。

类似这种用法,是会被浏览器忽略的。

这篇关于Vue学习笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!