vue学习

a

Vue 学习笔记

基础部分

var let const
var
	ES5 没有块级作用域概念
let
	ES6新增,增加块级作用域概念
const
	ES6新增,定义时必须赋值,且值不可改变,用来修饰常量

const a = 10;
a = 20; // a 不能修改

const

常量的含义是指向的对象不能被改变,但可以改变对象的值

<script>
    const obj = {
      name:'aaa',
      age:18
    }
    console.log(obj);
    obj.name='bbb';
    obj.age=30;
    console.log(obj);
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4BzPCb1c-1610960137092)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20201231144502359.png)]


Vue生命周期

Vue生命周期原图

Vue生命周期解析

beforeCreat() 创建前

created()() 创建后

beforeMount() 挂载前

mounted() 挂载后

beforeUpdate() 更新前

updated() 更新后

beforeDestry() 销毁前

destryed() 销毁后

第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子

created 与 mounted的区别

created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。

mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。

ES6 与 ES5 对比
属性增强写法
<script>
  /* ES5 */
  const obj = {
    name:'小龙人',
    age:18
  }
  console.log(obj);
  /* ES6 */
  const name = '小龙人';
  const age = 18;
  const person = {
    name,
    age
  }
  console.log(person);
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R73Crtj6-1610960137103)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20201231145700763.png)]

函数增强写法
<script>
  /* ES5 */
  const obj = {
    run:function () {

    },
    eat:function () {

    }
  }
  /* ES6 */
  const data = {
    run(){

    },
    eat(){

    }
  }
</script>

ES6 模块化开发导入与导出
    /* 在 aaa.js 中定义 name属性与sum函数 并导出 */
    let name = '张三';
    function sum(a,b){
      return a + b;
    }
    /* 导出对象 */
    export{
      name,sum
    }
    
    /* bbb.js 导入 aaa.js 导出的sum函数与name属性 */
    import {sum,name} from "./aaa.js";
    // 执行输出
    console.log(sum(10,20));
    console.log(name);
    <body>
    <!-- 主页面引入bbb.js type为 module -->
    <script src="bbb.js" type="module">

    </script>
    </body>

浏览器结果预览:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q2KNuRgV-1610960137105)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210103165838755.png)]

插值指令
1.v-once : 当 name 值改变时 ,标签内的值不会变化
	<p v-once>{{ name }}</p>

2.v-for : 遍历
    <p v-for=" item in scholl ">{{ item }}</p>
    data = {"北京","上海","天津"}

3.v-html : 填充html  
    <div>
        {{ url }}
    </div>
    data:{
        url:'<a src="www.baidu.com">百度</a>'
    }

4.v-text : 填充文本  
    <div>
        {{ url }}
    </div>
    data:{
        url:'今天天气不错啊!'
    }

绑定属性 v-bind
缩写: :  (冒号)
    <img v-bind:src="imgUrl" alt="">
    <!-- 缩写后,v-bind可省略 -->
    <img :src="imgUrl" alt="">	
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        new Vue({
            el:'#app',
            data:{
                name:'张三',
              imgUrl:'https://cn.vuejs.org/images/logo.png'
            },
        })
    </script>
动态绑定 class 属性 v-bind
(方式一)

   <style>
       .line{
         color:red
       }
       .stone{
         font-size: 30px;
        }
     </style>
   <div id="app">
     <!-- 通过 {} boolean判断该class属性的绑定与否 -->
       <p :class="{line:isline,stone:isstone}">今天天气不错</p>
   </div>
   <script src="https://cdn.jsdelivr.net/npm/vue"></script>
   <script>
       new Vue({
           el:'#app',
           data:{
             isline:true,
             isstone:true,
           },
       })
   </script>

(方式二)
   <div id="app">
     <!-- 通过 {} boolean判断该class属性的绑定与否 -->
       <p :class="getClass()">今天天气不错</p>
   </div>
   <script src="https://cdn.jsdelivr.net/npm/vue"></script>
   <script>
       new Vue({
           el:'#app',
           data:{
             isline:true,
             isstone:true,
           },
         methods:{
             getClass:function(){
               return {line:this.isline,stone:this.isstone}
             }
         }
       })
   </script>
练习——点击变色
<style>
    .active{
      color: red;
    }
  </style>
<div id="app">
  <ul>
    <li v-for="(food,index) in foods" @click="activeIndex = index" :class="{'active':activeIndex==index}"> {{ index }}----{{ food }}</li>
  </ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
    new Vue({
        el:'#app',
        data:{
          activeIndex:-1,
          foods:["杂酱面","捞面","海底捞","火锅"]
        }
    })
</script>
计算属性——computed

​ Methods 与 computed方法不能重名,重名使用methods定义的方法

​ Computed 为属性,调用时 使用属性名 例如; {{cur}} 而不是 {{cur()}}

​ Methods 调用时需要带()

 <!--  -->
<div id="app">
  <p>{{msg}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
    new Vue({
        el:'#app',
        data:{
          name:"小龙",
          age:18
        },
      <!--computed 会将数据转化后进行显示  -->
      computed:{
          msg:function(){
            return this.name + this.age + '岁'
          }
      }
    })
</script>
结论 :调用方法时.每次都需要进行计算,既然有计篇过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这一点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销。 
事件监听 v-on

缩写: @

<body>
<div id="app">
  <button v-on:click="run">btn1</button>
  <button @click="run">btn2</button>
  <!-- 在方法调用时,我们需要event对象但又需要其他参数,可使用 $event 手动获取浏览器的event对象 -->
  <button @click="eat('汉堡',$event)">btn2</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
    new Vue({
        el:'#app',

      methods:{
          run(){
            alert('runing....')
          },
        eat(food,event){
            alert('我在吃' + food)
          console.log(event);
        }
      }
    })
</script>
条件判断
<div id="app">
  <p v-if="score == 100">棒极了</p>
  <p v-else-if="score >= 80">还行啊</p>
  <p v-else-if="score >= 60">勉强及格</p>
  <p v-else>???</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
    new Vue({
      el:'#app',
      data:{
          score:90
      }
    })
</script>
显示切换 v-show
<div id="app">
    <!--
    v-if : 当条件为false时,包含v-if指令的元素根本不会存在dom中
    v-show : 根据 boolean 值 切换元素的显示方式  false 时 display:noe,元素存在dom中
	当 显示频率 切换比较高的时候 使用 v-show,当只有一次切换时 使用 v-if
   -->
  <p v-show="type">
    我该显示吗
  </p>
  <p v-if="type">
    我该显示吗
  </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
    new Vue({
        el:'#app',
      data:{
          type:true
      }
    })
</script>
数组响应式方法
<div id="app">
  <ul>
    <li v-for="item in names">{{ item }}</li>
  </ul>
  <button @click="change">点我</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
    new Vue({
        el:'#app',
        data:{
            names:['a','b','c','d']
        },
      methods:{
        change() {
          // 1.push() 方法 数组添加数据 可通过逗号分隔 添加多个值
          this.names.push('x');
          this.names.push('x','y','z');
          // 2.pop() 方法 数组添加数据
          this.names.pop('x');
          // 3.shift() 方法 删除数组的第一个元素
          this.names.shift();
          // 4.unshift() 方法 在数组最前面添加元素 可通过逗号分隔 添加多个值
          this.names.unshift('t');
          this.names.unshift('y','u','i');
          /*
           * 4.splice() 方法  可 删除、插入、替换元素
           * splice(start,nubmers,)
           * start: 起始位置
           * numbers:要删除及格元素,不传则删除后面所有元素
           * 替换元素:第二个参数表示我们要替换及格元素,后面是替换前面元素的内容
           */
          // [删除] 将 第一个元素后面的全部删除
          this.names.splice(1);
          // [替换] 从 第一个开始,删除 3 个元素 再将 'x','y','z','o' 填充达到数组中
          this.names.splice(1,3,'x','y','z','o');
          // [插入] 第二个参数为 0 ,后面跟上插入的元素 'x','y','z','o'
          this.names.splice(1,0,'x','y','z','o');
          // 5.sort() 方法 排序
          this.names.sort();
          // 6.reverse() 方法 数组反转
          this.names.reverse()

          // 非响应式 方法 通过索引值 改变数组中的元素
          this.names[0] = 'xxx';
          // 可使用 splice() 方法完成修改 变成响应式操作
          this.names.splice(0,1,'xxx');
          // set(要修改的元素,元素的下标,所要修改的值)
          Vue.set(this.name,0,'xxx');
        }
      }
    })
</script>
书籍购物车案例
<div id="app">
  // 当购物车内容不为空时显示
  <div v-if="books.length>1">
    <table>
      <thead>
      <tr>
        <th>名称</th>
        <th>出版日期</th>
        <th>价格</th>
        <th>购买数量</th>
        <th>操作</th>
      </tr>
      </thead>
      <tbody>
      <tr v-for="(item,index) in books">
        <td>{{item.title}}</td>
        <td>{{item.time}}</td>
        <td>¥{{item.price}}</td>
        <td>
          <button @click="less(index)" :disabled="item.count <=1 ">-</button>
          {{item.count}}
          <button @click="add(index)">+</button>
        </td>
        <td>
          <button @click="remove(index)">移除</button>
        </td>
      </tr>
      </tbody>
    </table>
    <h2>总价:¥ {{ totalPrice }}</h2>
  </div>
  // 购物车为空则显示当前数据
  <div v-else>
    <h2>购物车为空</h2>
  </div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
  new Vue({
    el: '#app',
    data: {
      books: [
        {
          title: 'java',
          time: '2020',
          price: '20',
          count: '1'
        },
        {
          title: 'php',
          time: '2020',
          price: '30',
          count: '1'
        },
        {
          title: 'python',
          time: '2011',
          price: '40',
          count: '1'
        },
        {
          title: 'C++',
          time: '2020',
          price: '50',
          count: '1'
        }
      ]
    },
    methods: {
      // 数量减少
      less(index) {
        this.books[index].count--;
      },
      // 数量增加
      add(index) {
        this.books[index].count++;
      },
      // 移除购物车
      remove(index) {
        this.books.splice(index, 1);
      }
    },
    // 通过计算属性 返回总价
    computed: {
      totalPrice() {
        let totalPrice = 0
        for (let i = 0; i < this.books.length; i++) {
          totalPrice += this.books[i].price * this.books[i].count;
        }
        return totalPrice;
        // 使用 reduce函数 返回
        return this.books.reduce(function (preValue,book) {
          return preValue + book.price * book.count;
        },0)
      }
    }
  })
</script>
* 高级函数 filter map reduce
<!-- 基础写法 -->
    <script>
      let arr = [10,20,30,50,100,200];
      console.log(arr)
      // 将 小于 100的元素返回
      let newArr = arr.filter(function(n){
        // 满足以下条件时,会将 n 添加到新的数组
        return n<100;
      })
      console.log(newArr)
      // 将数组内 每个元素 *2 再返回
      let doubleArr = arr.map(function(n){
        // 对 每个 n *2
        return n * 2;
      })
      console.log(doubleArr);
      // 返回数组累加的和
      let sumArr = arr.reduce(function (preValue,n) {
        return preValue + n;
      },0) // 0 表示 preValue的初始值
      console.log(sumArr)
    </script>
<!-- 进阶写法 -->
    <script>
      let arr = [10,20,30,50,100,200];
      console.log("数组初始数据:")
      console.log(arr)
      let newArr = arr.filter( n => n<100);
      console.log("小于 100:")
      console.log(newArr)
      let doubleArr = arr.map( n => n*2);
      console.log("双倍数值:")
      console.log(doubleArr)
      let sumArr = arr.reduce((preValue,n) => preValue + n);
      console.log("累加总和:")
      console.log(sumArr)
    </script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nTGJ2vo6-1610960137107)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20201231192729361.png)]

双向绑定 v-model
    <div id="app">
        <input type="text" v-model="msg">
        // 使用 v-value 与 v-on动态绑定事件可同样实现 数据双向绑定
        <input type="text" :value="msg" v-on:input="valueChange">
        <p>{{msg}}</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        new Vue({
            el:'#app',
            data:{
                msg:'张三'
            },
            methods:{
                valueChange(event){
                    this.msg = event.target.value;
                }
            }
        })
    </script>
v-model 结合 radio
    <div id="app">
        <input type="radio" value="" name="sex" v-model="sex">
        <input type="radio" value="" name="sex" v-model="sex">
        性别: {{ sex }}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        new Vue({
            el:'#app',
            data:{
                sex:''
            }
        })
    </script>
v-model 结合 checkbox
    <div id="app">
        <input type="checkbox" value="吃饭" name="sex" v-model="sex">吃饭
        <input type="checkbox" value="看电影" name="sex" v-model="sex">看电影
        <input type="checkbox" value="玩游戏" name="sex" v-model="sex">玩游戏
        <input type="checkbox" value="吃零食" name="sex" v-model="sex">吃零食br <br/>
        爱好: {{ sex }}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        new Vue({
            el:'#app',
            data:{
                /* 数组类型 */
                sex:[]
            }
        })
    </script>
v-model 结合 select
    <div id="app">
        <select name="d" id="" v-model="msg">
            <option value="吃饭">吃饭</option>
            <option value="玩游戏">玩游戏</option>
            <option value="打豆豆">打豆豆</option>
        </select>
        <p>选择的是:{{msg}}</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        new Vue({
            el:'#app',
            data:{
                /* 数组类型 */
                msg:''
            }
        })
    </script>
v-model 修饰符
    <div id="app">
        <!-- 1.lazy  当用户输入完成(input失去焦点 或 用户按下回车) 更新绑定的数据 -->
        <input type="text" v-model.lazy="msg">
        <p>输入的是:{{msg}}</p>
        <!-- 2.number 会将用户输入的数据转为数组 -->
        <input type="text" v-model.number="count">
        <p>输入类型:{{typeof count}}</p>
        <!-- 2.trim 取出数据左右两端的空格-->
        <input type="text" v-model.trim="msg">
        <p>输入类型:{{msg}}</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        new Vue({
            el:'#app',
            data:{
                /* 数组类型 */
                msg:'小爱同学',
                count:'dsada'
            }
        })
    </script>

Vue组件

    <div id="app">
        // 自定义组件名称
        <cpm></cpm>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        Vue.component('cpm', {
            template:'<div>' +
                    '<h1>我是标题</h1>' +
                    '<h1>我是文本</h1>' +
                    '</div>'
        });
    </script>
模板分离写法
    <div id="app">
        {{ name }}
        <cpm></cpm>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <!-- 1.使用 text/x-template 通过id绑定到 template-->
    <script type="text/x-template" id="cpn">
        <div>
            <h1>我是标题1</h1>
            <h1>我是内容1</h1>
        </div>
    </script>
    <!-- 2.使用<template> 标签 -->
    <template id="cpn2">
        <div>
            <h1>我是标题2</h1>
            <h1>我是内容2</h1>
        </div>
    </template>
    <script>

        Vue.component('cpm', {
            // 通过id获取
            template:id='#cpn'
        });
        new Vue({
            el:'#app',
            data:{
                name:'张三'
            },
        })
    </script>
父子组件的通信

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dZn7Ex0i-1610960137108)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210102161813208.png)]

父传子
    <div id="app">
        <!--
        1.mvs 绑定的是 data中 movies 的数据
        2.message绑定的是 data中 msg 的数据
        3.将 绑定名称传入组件,由 props接收 并在子组件中使用
        -->
        <cpn v-bind:mvs="movies" :message="msg"></cpn>
    </div>
    <template id="cpn">
        <div>
            <!-- 使用 父组件传递来的数据 -->
            <ul>
                <li v-for="item in mvs">{{item}}</li>
            </ul>
            <h1>{{msg}}</h1>
        </div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>

        Vue.component('cpn', {
            props:['mvs','message'],
            template:id='#cpn'
        });

         // props 的另一种写法
            props:{
                mvs:{
                    // 指定 mvs(key值) 的类型 可选 有String\Nbumer\Object\Boolean\Data\Function 多种可选
                    type:Array,
                    // 传递是 不可为空
                    required:true,
                    // 默认值
                    default:[]
                }
            },

        new Vue({
            el:'#app',
            data:{
                msg:'今天是个好天气',
                movies:['海王','盗墓笔记','鬼吹灯']
            },
        })
    </script>
子传父(自定义事件 $item)
    <div id="app">
        <!--
        1.fclick 为 子组件中自定义的事件名   this.$emit('fclick',item);
        2.parclick 为 父组件的事件名 在vue的methods中
        -->
        <cpn @fclick="parclick"></cpn>
    </div>
    <template id="cpn">
        <div>
            <!-- childck 为子组件的methods 参数为当前 item 对象 -->
            <button v-for="item in list" @click="childck(item)">{{item.name}}</button>
        </div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>

        Vue.component('cpn', {
            // 函数式 自定义数据格式
            data(){
                return{
                    list:[
                        {id:1,name:'中国移动'},
                        {id:2,name:'中国电信'},
                        {id:3,name:'中国联通'}
                    ]
                }
            },
            template:id='#cpn',
            // 自定义事件 向父组件传递数据  fclick 为事件名 在 <cpn @fclick="parclick"></cpn> 使用
            methods:{
                childck(item){
                    this.$emit('fclick',item);
                }
            }
        });
        new Vue({
            el:'#app',
            methods:{
                parclick(item){
                    console.log("fck" + item);
                }
            }
        })
    </script>

	<!-- 写法二: -->

    <div id="app">
        <cpn :item="movies" @parclick="par"></cpn>
    </div>
    <template id="cpn">
        <div>
            <!--                                  child(item) 必须传参-->
            <button v-for="movie in item" @click="child(item)">{{movie.name}}</button>
        </div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        Vue.component('cpn',{
            template:id='#cpn',
            props:['item'],
            methods:{
                child(item){
                    this.$emit('parclick',item)
                }
            }
        })
        new Vue({
            el:'#app',
            data:{
                name:'张三',
                movies:[
                    {id:1,name:'移动'},
                    {id:1,name:'电信'},
                    {id:1,name:'联通'}
                ]
            },
            methods:{
                par(item){
                    console.log(item)
                }
            }
        })
    </script>
父子组件的访问
父访问子 c h i l d r e n 与 children与 childrenrefs
    <div id="app">
        <div>
            <cpn></cpn>
            <cpn ref="aaa"></cpn>
            <cpn></cpn>
            <button @click="ck">按钮</button>
        </div>
    </div>
    <template id="cpn">
        <div>
            <p>我是一个子组件</p>
        </div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        new Vue({
            el:'#app',
            data:{
                name:'张三'
            },
            components:{
                cpn:{
                    template:id="#cpn",
                    data(){
                        return "我是子组件的 data信息"
                    }
                }
            },
            methods:{
                ck(){
                    // $children 通常用于 获取该组件的 所有 子组件
                    console.log(this.$children);
                    // $refs 可在子组件中 绑定 ref属性并获得该子组件 <cpn ref="aaa"></cpn>
                    console.log(this.$refs);
                }
            }
        })
    </script>					
子访问父 $parent 与 $root
<!-- 自行百度 -->

插槽 slot

提升组件的复用性

    <div id="app">
        <cpn>
            <!-- 替换插槽的内容 -->
            <div>P里有个div</div>
        </cpn>
        <cpn>
            <!-- 替换插槽的内容 -->
            <h1>cpn 里 有个h1</h1>
        </cpn>
    </div>
    <template id="cpn">
        <div>
            <p>这是一个P</p>
            <!-- 使用插槽占位 -->
            <slot>
            	<button>
                    插槽默认值
                </button>
            </slot>
        </div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        new Vue({
            el:'#app',
            data:{
                name:'张三'
            },
            components:{
                cpn:{
                    template:id="#cpn"
                }
            }
        })
    </script>
具名插槽的使用

通过指定 slot 的name属性 替换指定的插槽

    <div id="app">
        <cpn>
            <!-- 替换指定name属性的插槽 -->
            <span slot="center">被替换了吧</span>
        </cpn>
    </div>
    <template id="cpn">
        <div>
            <p>这是一个P</p>
            <!-- 插槽 绑定name属性  -->
            <slot name="left"><span>左边</span></slot>
            <slot name="center"><span>中间</span></slot>
            <slot name="right"><span>右边</span></slot>
        </div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        new Vue({
            el:'#app',
            data:{
                name:'张三'
            },
            components:{
                cpn:{
                    template:id="#cpn"
                }
            }
        })
    </script>
作用域插槽

父组件替换插槽的内容

    <div id="app">
        <cpn>
            <!-- slot-scope="slot" 获取插槽对象 -->
            <template slot-scope="slot">
                <ol>
                    <!-- slot.data 获取当前插槽对象的data属性 data命名可自定义 -->
                    <li v-for="item in slot.data">{{item}}</li>
                </ol>
            </template>
        </cpn>
    </div>
    <template id="cpn">
        <div>
            <!-- 绑定数据,将languages绑定给 data 为上面获取属性使用,可随便命名 -->
            <slot :data="languages">
                <ul>
                    <li v-for="item in languages">{{item}}</li>
                </ul>
            </slot>
        </div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        new Vue({
            el:'#app',
            data:{
                name:'张三'
            },
            components:{
                cpn:{
                    template:id="#cpn",
                    data(){
                        return{
                            languages:['java','c','c++','javascript']
                        }
                    }
                }
            }
        })
    </script>

Webpack

跳过 直接开脚手架了。https://www.bilibili.com/video/BV15741177Eh?p=77

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I3ADwE3N-1610960137110)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104110432895.png)]

vue-cli2

安装:
npm install -g @vue/cli
查看 vue 版本
vue --verison  
初始化项目
vue init webpack [项目名称]

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

尝试启动
cd vue-el
npm run dev  启动成功!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vNwR2E2B-1610960137113)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104150341438.png)]

安装遇到错误:

删除 C:\Users\XQi\AppData\Roaming 下的 npm-cache文件夹

npm clean cache --force
重新进行vue-cli安装。
Eslint规范

​ 用于控制代码编写标准规范。

runtime-compiler与runtime-only区别

https://www.bilibili.com/video/BV15741177Eh?p=96

// runtime-compiler  vue运行过程
vdom 为 virtual dom(虚拟 dom)
template -> ast -> render -> v DOM -> ui

  将 template(模板) 解析为 ast (abstract syntax tree) 抽象语法树 ,ast 编译为 render函数 ,从 render函数创建虚拟DOM节点形成虚拟DOM树,最终显示为真实DOM

// runtime-only 省略了 将模板解析文 ast的过程
render > v DOM > ui

总结:runtime-only 代码更少性能更高
   [main.js] 代码区别如下
	/* runtime-compiler */
    new Vue({
      el: '#app',
      components: { App },
      template: '<App/>'
    })
    /* runtime-only */
    new Vue({
      el:'#app',
      render:h => h(App)
    })

vue-cli3

安装

1.卸载现有 vue-cli

npm uninstall vue-cli -g

2.安装新的vue-cli

npm install -g @vue/cli

3.查看版本,应该是 3.xxx

vue --version
初始化项目
vue create [项目名称]

选择配置:

img

一开始只有两个选项: default(默认配置)和Manually select features(手动配置)
默认配置只有babeleslint其他的都要自己另外再配置,所以我们选第二项手动配置。
在每次选择手动配置之后,会询问你是否保存配置,也就是图片中的koro选项,这样以后我们在进行创建项目的时候只需使用原先的配置就可以了,而不用再进行配置。

根据项目需要来选择配置,空格键是选中与取消,A键是全选

? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection) 
// 检查项目所需的功能:(<space>选择,<a>切换所有,<i>反转选择)
>( ) TypeScript                                 // 支持使用 TypeScript 书写源码
 ( ) Progressive Web App (PWA) Support          // PWA 支持
 ( ) Router                                     // 支持 vue-router
 ( ) Vuex                                       // 支持 vuex
 ( ) CSS Pre-processors                         // 支持 CSS 预处理器。
 ( ) Linter / Formatter                         // 支持代码风格检查和格式化。
 ( ) Unit Testing                               // 支持单元测试。
 ( ) E2E Testing  

如果你选择了Css预处理器选项,会让你选择这个

完成后打开项目!

npm run serve  // 启动项目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-heJJiTFY-1610960137115)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104165443734.png)]

图形化创建项目

命令行输入,进入创建页面,然后就是无脑的手动操作,此处略过

vue ui

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bgCpf1FB-1610960137117)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104165552624.png)]

vue-cli3 的配置
vue ui  // 进入图形化界面,导入项目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5lu9cdeJ-1610960137117)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104171101075.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ogRcGy7-1610960137118)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104171112915.png)]

安装指定版本的vue-cli

卸载当前版本;
npm uninstall -g @vue/cli
安装新版本:
npm install -g @vue/cli@版本号
例如:
npm install -g @vue/cli@3.2.1

箭头函数(ES6)

    <script>
      // 普通写法
      function sum(a,b){
        return a + b;
      }
      // 调用
      sum(10,20)

      //Es6 x函数计算 a与b的和
      let x = (a,b) => a + b;
      console.log(x(10,20));

      // 当只有一个参数时
      let y = (x) => {
        return x * x
      }
      // 只有一个参数小括号可省略
      let y = x => {return x * x}

      // 只有一行代码时 , {} 也可以省略
      let z = n => n*2



      console.log( y(20) );

    </script>

Vue-Router

基本概念
后端路由概念
当页面需要请求不同的路径时,交给服务器来进行处理,服务器渲染好整个页面并将页面返回给客户端。
前后端分离阶段
后端只负责提供数据,不负责提供给任何界面的内容。
前端渲染
网页中大部分内容都是有前端js代码在浏览器中执行,最终渲染出的网页。
SPA页面
单页面应用	single page web application
在前后端分离基础上 增加 前端路由,前端来维护路由规则
url 与 页面 对应关系 由前端管理
前端路由核心
改变url,但是页面不进行整体刷新
官方网址:

​ https://router.vuejs.org/zh/

安装与使用
安装
npm install vue-router --save

使用: src目录下 创建 router目录,并新增 index.js

/**
 * 配置所有的路由信息
 */

// 导入Vue 与 VueRouter
import Vue from 'vue'
import VueRouter from 'vue-router'
// 1.通过Vue.use(插件) 安装插件
Vue.use(VueRouter);
// 2.创建路由对象
const routers = [

]
const router = new VueRouter({
  // routers 负责配置组件质之间的映射关系
  routers
})
// 3.将router传入 Vue实例中

export default router	

在 main.js 导入并使用路由

import Vue from 'vue'
import App from './App'
// 导入路由
import router from "./router";

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  // 使用路由
  router,
  components: { App },
  template: '<App/>'
})
使用步骤

1.创建路由组件 在conponents 目录下 创建 about与home组件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EEGTV94O-1610960137120)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104220143066.png)]

<!-- home.vue 内容如下 -->
<template>
  <div>
    <h2>我是首页</h2>
  </div>
</template>

<script>
  export default {
    name: "home"
  }
</script>

<style scoped>

</style>


<!-- about.vue 内容如下 -->
    
<template>
  <div>
    <h2>我是About</h2>
  </div>
</template>

<script>
  export default {
    name: "about"
  }
</script>

<style scoped>

</style>

2.配置路由映射:组件和路径映射关系

/**
 * 配置所有的路由信息
 */

// 导入Vue 与 VueRouter
import Vue from 'vue'
import VueRouter from 'vue-router'

// 导入组件
import home from "../components/home";
import about from "../components/about";
// 1.通过Vue.use(插件) 安装插件
Vue.use(VueRouter);
// 2.创建路由对象
const routes = [
  // path 为 组件路径,component 为具体组件 上方有引入
  {
    path:'/home',
    component:home
  },
  {
    path: '/about',
    component: about
  }
]
const router = new VueRouter({
  // routes 负责配置组件质之间的映射关系,Es6 写法
  routes
})
// 3.将router传入 Vue实例中

export default router

3.使用路由,通过 和

<template>
  <div id="app">
    <!-- to 表示指向组件路径 -->
    <router-link to="/home">首页</router-link>
    <router-link to="/about">关于</router-link>
    <!-- 组件内容渲染位置 -->
    <router-view></router-view>
  </div>
</template>

<script>

export default {
  name: 'App',
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

效果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2nmKKkQN-1610960137121)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104220515644.png)]

默认路径与

修改 启动 默认路径

routes 中 配置
// 默认路径重定向 到 home首页
  {
    path:'',
    redirect:'/home'
  },

# 删除
const router = new VueRouter({
  // routers 负责配置组件质之间的映射关系
  routes,
  // 省去 url中的 # 号
  mode:'history'
})
router-link的其他属性
<div id="app">
    <!-- to 表示指向组件路径 -->
    <router-link to="/home">首页</router-link>
    <router-link to="/about">关于</router-link>
    <!-- tag属性 会将 router-link以指定组件方式渲染,此处渲染为 button-->
    <router-link to="/home" tag="button">首页</router-link>
    <router-link to="/about" tag="button">关于</router-link>
    <!-- replace属性 不会留下history记录,使用该属性无法点击返回按钮返回上一级-->
    <router-link to="/home" replace>首页</router-link>
    <router-link to="/about" replace>关于</router-link>
    <!-- active-class属性 当该组件被点击后,处于活跃状态,会为当前元素设置 一个 router-link-active 的class -->
    <!-- 在进行 高亮显示 时会使用该属性 无需手动增加-->
    <router-link to="/home">首页</router-link>
    <router-link to="/about">首页</router-link>
    <!-- 组件内容渲染位置 -->
    <router-view></router-view>
  </div>
    <style>
       // 直接进行 高亮渲染
      .router-link-active{
        color: red;
      }
    </style>
通过代码实现跳转
	<!-- 通过代码方式 跳转路径 -->
    <button @click="homeClick">首页</button>
    <button @click="aboutClick">关于</button>
    <!-- 组件内容渲染位置 -->
    <router-view></router-view>
	<script>
    export default {
      name: 'App',
      methods:{
        homeClick(){
          // $router 为 vue-router源码自带属性
          this.$router.push('/home');
          // replace 不支持 浏览器 返回
          this.$router.replace('/home');
        },
        aboutClick(){
          this.$router.push('/about');
          this.$router.replace('/about');
        }
      }
    }
	</script>

动态路由

<template>
<div>
  <h2>我是用户</h2>
  <!-- $route 为当前活跃路由 截取传递来的参数,id为参数名  -->
  <h1>{{$route.params.id}}</h1>
</div>
</template>

<script>
  export default {
    name: "user"
  }
</script>

<style scoped>

</style>

路由对象配置:

const routes = [
  // 默认路径重定向 到 home首页
  {
    path:'',
    redirect:'home'
  },
  // path 为 组件路径,component 为具体组件 上方有引入
  {
    path:'/home',
    component:home
  },
  {
    path: '/about',
    component: about
  },
    // 传递参数 参数名 为 id
  {
    path: '/user/:id',
    component: user
  }
]

App.vue配置:

<template>
  <div id="app">
    <!-- to 表示指向组件路径 -->
    <router-link to="/home">首页</router-link>
    <router-link to="/about">关于</router-link>
     <!-- 动态获取id,通过v-bind 内部进行拼接-->
    <router-link :to="'/user/'+id">用户</router-link>

    <!-- 组件内容渲染位置 --> 
    <router-view></router-view>
  </div>
</template>

<script>
  export default {
    name:'App',
    data(){
      return{
        id:123
      }
    }
  }

</script>
路由懒加载

​ 当打包构建应用时,js文件较大,加载缓慢,影响页面加载。

​ 我们把不同的路由组件分割为不同的代码模块,当路由访问时,去加载对应组件,这就是懒加载。

懒加载效果图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lXe1zcrN-1610960137122)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210105105112245.png)]

具体实现

const home = () => import('../components/home.vue)
const about = () => import('../components/about')
const user = () => import('../components/user')'
const routes = [
  // 默认路径重定向 到 home首页
  {
    path:'',
    redirect:'home'
  },
  // path 为 组件路径,component 为具体组件 上方有引入
  {
    path:'/home',
    component:home
  },
  {
    path: '/about',
    component: about
  },
  {
    path: '/user/:id',
    component: user
  }
]
路由嵌套

路径与组件关系如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SOydupkl-1610960137123)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210105105856660.png)]

// home 路径下 有两个 子组件 ,
{
    path:'/home',
    component:home,
    children:[
      // 设置子组件默认路径 path 的 / 可省略
      {
        path: '',
        redirect:'news'
      },
      {
        path:'news',
        // 懒加载 导入组件
        component: () => import('../components/homeNews')
      },
      {
        path: 'message',
        component:()=> import('../components/homeMessage')
      }
    ]
  },
```

```vue
<template>
  <div>
    <h2>我是首页</h2>
    <!-- 添加 路由显示 -->
    <router-link to="/home/news">新闻</router-link>
    <router-link to="/home/message">消息</router-link>
    <router-view></router-view>
  </div>
</template>

<script>
  export default {
    name: "home"
  }
</script>

<style scoped>

</style>
```

#### 参数传递

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Q0FXeZW-1610960137125)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210105112300311.png)]

创建 profile.vue 组件

```vue
<template>
  <div>
    <h1>我是一个档案,嘿嘿嘿</h1>
    <!-- 获取路由传递的 query字段 -->
    <h2>{{$route.query}}</h2>
    <!-- 获取路由传递的 query字段 的指定参数 -->
    <h2>{{$route.query.name}}</h2>
  </div>
</template>

<script>
  export default {
    name: "proFile"
  }
</script>

<style scoped>

</style>
```

index.js 增加组件配置

```javascript
{
    path: '/profile',
    component:() => import('../components/proFile')
  }
```

App.vue配置路由

```javascript
<template>
  <div id="app">
    <!-- to 表示指向组件路径 -->
    <router-link to="/home">首页</router-link>
    <router-link to="/about">关于</router-link>
    <router-link :to="'/user/'+id">用户</router-link>
	<!-- 以 query方式传递参数 -->
    <router-link :to="{path:'/profile',query:{name:'张三',age:18}}">档案</router-link>

    <!-- 组件内容渲染位置 -->
    <router-view></router-view>
  </div>
</template>
```

#### $router 与 $route 的区别

**$router为当前 vue实例,想要导航到不同的url,使用$router.push 方法**

**$route为当前活跃 route,可从跳转对象中获取name、parms、path、query等相关信息**

[参考 vue-router源码]

#### vue-router全局导航守卫

**导航守卫?:  负责监听路由的跳转**

##### 生命周期函数补充说明

  created()   当组件创建时 执行

  mounted() 组件 被挂载时执行

  updated()  组件刷新时执行

##### 导航守卫实现——前置钩子

**router/index.js**

```javascript
/**
 * 配置所有的路由信息
 */

// 导入Vue 与 VueRouter
import Vue from 'vue'
import VueRouter from 'vue-router'

// 导入组件
import home from "../components/home";
import about from "../components/about";
import user from "../components/user";


// 1.通过Vue.use(插件) 安装插件
Vue.use(VueRouter);
// 2.创建路由对象
const routes = [
  // 默认路径重定向 到 home首页
  {
    path:'',
    redirect:'/home/news'
  },
  // path 为 组件路径,component 为具体组件 上方有引入
  {
    path:'/home',
    component:home,
    // 设置当前页面title名称
    meta:{
      title:'首页'
    },
    children:[
      {
        path: '',
        redirect:'/home/news'
      },
      {
        path:'news',
        component: () => import('../components/homeNews')
      },
      {
        path: 'message',
        component:()=> import('../components/homeMessage')
      }
    ]
  },
  {
    path: '/about',
    component: about,
    meta:{
      title:'关于'
    },
  },
  {
    path: '/user/:id',
    component: user,
    meta:{
      title:'用户'
    },
  },
  {
    path: '/profile',
    component:() => import('../components/proFile'),
    meta:{
      title:'档案'
    },
  }
]
const router = new VueRouter({
  // routers 负责配置组件质之间的映射关系
  routes,
  // 省去 url中的 # 号
  mode:'history'
})


// 3.将router传入 Vue实例中

export default router
```

**main.js**

```javascript
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
// 导入路由
import router from "./router";
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  // 使用路由
  router,
  components: { App },
  template: '<App/>'
})
// 配置 导航守卫  beforeEach 前置钩子
router.beforeEach(function (to,from,next) {
  // 将当前页面(to) title 设置为 目标路由(form)的title
    // matched.neta.title 防止路由嵌套 无法获取正确的 title
  document.title = to.matched[0].meta.title
  // 必写,next()函数中可填写url,跳转指定的路径
  next()
})
// Es6 写法
router.beforeEach((to,from,next) => {
  document.title = to.matched[0].meta.title
  // 必写
  next()
})

})
```

##### 导航守卫实现——后置钩子

router**.beforeEach(to,from,next)**  变为 router.**afterEach(to,from)**

##### 官网教程

> https://router.vuejs.org/zh/guide/advanced/navigation-guards.html

##### 路由独享守卫

```javascript
const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})
```

##### 组件内的守卫

```javascript
const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}
```

#### keep-alive

> vue生命周期,保持组件不被频繁创建、频繁销毁·

```vue
<template>
  <div id="app">
    <!-- to 表示指向组件路径 -->
    <router-link to="/home">首页</router-link>
    <router-link to="/about">关于</router-link>
    <router-link :to="'/user/'+id">用户</router-link>
    <router-link :to="{path:'/profile',query:{name:'张三',age:18}}">档案</router-link>
    <keep-alive>
      <!-- 组件内容渲染位置 -->
      <router-view></router-view>
    </keep-alive>
  </div>
</template>
```

**相关属性**

```javascript
<!--
     include:只有 匹配的组件不会被缓存,
     exclude:任何匹配的组件都不会缓存
     属性内填写组件的name属性,user为组件中 name为 user的组件
     -->
    <keep-alive exclude="profile,user">
      <!-- 组件内容渲染位置 -->
      <router-view></router-view>
    </keep-alive>



    // 组件详情
    <template>
    <div>
      <h2>我是用户</h2>
      <!-- $route 为当前活跃路由 截取传递来的参数,id为参数名  -->
      <h1>{{$route.params.id}}</h1>
    </div>
    </template>

    <script>
      export default {
        name: "user"
      }
    </script>

    <style scoped>

    </style>

```

#### 代码练习:tabbar

> https://gitee.com/iQeKiaLieW/tabbar.git[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-78adcAIb-1610960137126)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210105163946688.png)]

### Promise(ES6)

> ​	处理异步操作。使用promise对异步请求进行封装

***

```javascript
    <script>
      /*
      *  new -> 构造函数(1.保存状态信息2.执行传入的函数)
      */
      new Promise((resolve,reject) => {
        // resolve 仅负责异步请求
        resolve('hello world')
        // 成功时调用 resolve,失败时调用 reject
        reject('error message')
        // then 负责 处理异步请求的 数据
      }).then(data => {
        console.log(data); // 输出 hello world
        // catch 负责处理请求失败的操作
      }).catch(err => {
        console.log(err);  // 输出 error message
      })
    </script>
```

##### 三种状态

> pending:等待状态,比如正在进行网络请求,定时器没有到时间
>
> funfill: 满足状态,当我们主动调用 resolve() 会处于 满足状态,并回调 then()
>
> reject: 拒绝状态,当我们主动调用 reject() 会处于 满足状态,并回调 catch()

##### 另外处理方式

```javascript
    <script>
        new Promise((resolve,reject) => {
          setTimeout(() => {
            //resolve('SUCCESS');
            reject('ERROR');
          },1000)
      // then 中 可同时处理 请求成功回调与请求失败回调,以两个参数传入,第一个参数为成功回调,第二个参数为失败回调
      }).then(data =>{
        console.log(data)
      },err => {
        console.log(err)
      })
    </script>
```



### Promise的 all 方法

> 当 A 请求需要 B请求与C请求请求完成后才可以发送请求,使用一下方法。

```javascript
    <script>
      Promise.all([
          new Promise((resolve,reject) => {
            $.ajax({
              url:'url1',
              success(data){
                resolve(data);
              }
            })
            $.ajax({
              url:'url2',
              success(data){
                resolve(data);
              }
            })
          }).then( results =>{
            // results 为一个数组,存放上面两个请求的 响应结果
            // results[0] 为第一个请求的结果,results[1] 为第二个请求的结果
            console.log(results[0]);
            console.log(results[1]);
          })
      ])
    </script>
```



### Vue X

***

> 定义: 状态管理工具,管理共享数据,比如用户登录状态、名称、头像等。

#### 下载使用

```bash
npm install vuex --save
```

**创建 store 文件夹,创建index.js**

```javascript
import Vue from 'vue'
// 导入 vuex
import Vuex from 'vuex'
// 使用插件
Vue.use(Vuex)

// 创建对象 Store大写
const store = new Vuex.Store({
  // 状态(数据)存放
  state:{
    count:0
  },
  // 函数处理
  mutations:{
    increment(state){
      state.count ++;
    },
    decrement(state){
      state.count --;
    }
  }
})
// 导出 store
export default store
```

**main.js中 使用 store**

```javascript
import Vue from 'vue'
import App from './App'
// 导入 store
import store from "./store";
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  // 使用 store
  store,
  render: h => h(App)
})
```

**数据展示及处理**

```vue
<template>
  <div id="app">
    <div>
      <p>—————————————Div内容———————————————</p>
      <!-- 在 vue组件中 获取 vuex状态 -->
      <h2>{{$store.state.count}}</h2>
      <button @click ="add"> + </button>
      <button @click="sub"> - </button>
    </div>
  </div>
</template>

<script>
  import HelloVuex from "./components/HelloVuex";
export default {
  name: 'App',
  comments:{
    HelloVuex
  },
  methods:{
    // 使用 commit 调用 括号内的函数
    add(){
      this.$store.commit('increment');
    },
    sub(){
      this.$store.commit('decrement');
    }
  }
}
</script>

<style>

</style>
```

#### 核心概念

>1.State 	单一状态树,一个项目只有一个 store
>
>2.Getters  类似计算函数(computed),
>
>3.Mutation  当修改 Store中的 State,必须通过 Mutation
>
>4.Action		处理异步操作
>
>5.Module

##### Getters使用

```javascript
state:{
    count:0,
    player:[
      {id:110,name:'aaa',age:10},
      {id:111,name:'bbb',age:15},
      {id:112,name:'ccc',age:20},
      {id:113,name:'ddd',age:25}
    ]
  },

// 响应式计算 count 的乘积
    getters:{  
        powerCount(state){
          return state.count * state.count;
        },
        // 返回 小于 10 岁的 运动员
        lessAge (state){
          return state.player.filter( p => p.age<=10)
        },
        // 返回 小于 10 岁的 运动员的 长度
        lessAgeLength (state){
          return state.player.filter( p => p.age<=10).length;
        },
        // 返回 小于 10 岁的 运动员的 长度
        length(state,getters){
          // 通过传入 getters 返回
          return getters.lessAge.length;
        },
        // 返回小于指定 age 的数据
        lessLength(state){
          // 嵌套函数
          return age => {
            return state.player.filter( p => p.age<=age)
          }}
  	},
      
调用并显示:$store.getters.xxxx
<div id="app">
    <div>
      <p>—————————————Div内容———————————————</p>
      <!-- 在 vue组件中 获取 vuex状态 -->
      <h2>{{$store.state.count}}</h2>
      <button @click ="add"> + </button>
      <button @click="sub"> - </button>
      <p>—————————————Getters相关信息———————————————</p>
      <h2>{{$store.getters.powerCount}}</h2>
      <p>—————————————Getters小于 20岁球员———————————————</p>
      <h1>{{$store.getters.lessAge}}</h1>
      <p>—————————————Getters的长度———————————————</p>
      <h1>{{$store.getters.length}}</h1>
      <p>—————————————Getters小于指定age———————————————</p>
      <h1>{{$store.getters.lessLength(20)}}</h1>
    </div>
```

##### Mutations的使用

**定义**

```javascript
mutations:{
    increment(state){
      state.count ++;
    },
    decrement(state){
      state.count --;
    }
  }
```

**调用**

```javascript
methods:{
    // 使用 commit 调用 括号内的函数
    add(){
      this.$store.commit('increment');
    },
    sub(){
      this.$store.commit('decrement');
    }
  }
```

**传递参数**

```javascript
	  <button @click="addCount(5)"> +5 </button>
      <button @click="addCount(10)"> +10 </button>
      <button @click="addPlayer"> 添加球员 </button>
// 传递参数,num
    addCount(num){
      this.$store.commit('addCount',num);
    },
    // 传递对象
    addPlayer(){
      const player = {id:1000,name:'xxxx',age:1};
      this.$store.commit('addPlayer',player);
    }

<!--mutations  定义-->

mutations:{
    // 增加指定数值
    addCount(state,num){
      state.count = state.count + num;
    },
    // 添加对象
    addPlayer(state,player){
      state.player.push(player);
    }
  }
```

**提交分格**

```javascript
	addCount(num){
      // 普通写法
      this.$store.commit('addCount',num);
	  // 新写法 格式: this.$store.commit('',payload)  
      this.$store.commit({
        type:'addCount',
        num
      });
       

    },


	// 增加指定数值(普通)
    addCount(state,num){
      state.count = state.count + num;
    },
    // 新写法
    addCount(state,payload){
      state.count = state.count + payload.num;
    },
```

##### Actions的使用 

> ​	在 Mutations处理异步请求无法实现,故在Actions中使用

```javascript

actions:{
    aRename(content){
      setTimeout(()=>{
        // 最终 都要 commit 到 Mutations中处理
        content.commit('rename');
      },2000)
    }
  }

// App.vue  methods中写法:
	methods:{
        rename(){
          // 使用 dispatch 调用 action中的方法
          this.$store.dispatch('aRename');
        }
    }
```



##### Modules的使用

> ​	store 模块化封装

```javascript
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 的状态
```



>  官网链接  https://vuex.vuejs.org/zh/guide/modules.html

***

### 网络请求封装 axios

##### 下载使用

```bash
npm install axios --save
```

```javascript
axios({
  url:'http://123.207.32.32:8000/home/multidata'
}).then(res => {
  console.log(res);
})

axios({
  url:'http://123.207.32.32:8000/home/data',
  // 可 在 url直接拼接参数,也可配置 params添加参数
  params:{
    type:'sell',
    page:2
  }
}).then(res => {
  console.log(res);
})
```

##### 发送并行请求 axios.all()

```javascript
axios.all([axios(
  {
    url:'http://123.207.32.32:8000/home/multidata'

  }
),axios(
  {
    url:'http://123.207.32.32:8000/home/data',
    params:{
      type:'sell',
      page:2
    }
  }
)]).then( results => {
  console.log(results);
})
```

##### 全局配置

```javascript
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
```

> 官方文档——http://www.axios-js.com/zh-cn/docs/#%E5%85%A8%E5%B1%80%E7%9A%84-axios-%E9%BB%98%E8%AE%A4%E5%80%BC

##### axios实例封装



```javascript
import axios from "axios";
export function request(config) {
  // 创建axios实例对象
  const instance = axios.create({
    baseURL:'http://123.207.32.32:8000',
    timeout:5000
  })
  // 基本写法
  return new Promise((resolve,reject) => {
    instance(config).then(result => {
      resolve(result);
    }).catch(error => {
      reject(error);
    })
  })
  // 优于 axios 内置了 Promise,所以直接返回即可
  return instance(config);
}
```

> 调用

```javascript
request({
  url:'/home/multidata'
}).then(res => {
  console.log(1);
  console.log(res);
})
```

##### axios 拦截器

```javascript
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });
```

**ajax实例添加拦截器**

```javascript
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});

```

**错误处理**

```javascript
axios.get('/user/12345')
  .catch(function (error) {
    if (error.response) {
      // The request was made and the server responded with a status code
      // that falls out of the range of 2xx
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.headers);
    } else if (error.request) {
      // The request was made but no response was received
      // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
      // http.ClientRequest in node.js
      console.log(error.request);
    } else {
      // Something happened in setting up the request that triggered an Error
      console.log('Error', error.message);
    }
    console.log(error.config);
  });
```

发送并行请求 axios.all()

```javascript
axios.all([axios(
  {
    url:'http://123.207.32.32:8000/home/multidata'

  }
),axios(
  {
    url:'http://123.207.32.32:8000/home/data',
    params:{
      type:'sell',
      page:2
    }
  }
)]).then( results => {
  console.log(results);
})
```

##### 全局配置

```javascript
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
```

> 官方文档——http://www.axios-js.com/zh-cn/docs/#%E5%85%A8%E5%B1%80%E7%9A%84-axios-%E9%BB%98%E8%AE%A4%E5%80%BC

##### axios实例封装



```javascript
import axios from "axios";
export function request(config) {
  // 创建axios实例对象
  const instance = axios.create({
    baseURL:'http://123.207.32.32:8000',
    timeout:5000
  })
  // 基本写法
  return new Promise((resolve,reject) => {
    instance(config).then(result => {
      resolve(result);
    }).catch(error => {
      reject(error);
    })
  })
  // 优于 axios 内置了 Promise,所以直接返回即可
  return instance(config);
}
```

> 调用

```javascript
request({
  url:'/home/multidata'
}).then(res => {
  console.log(1);
  console.log(res);
})
```

##### axios 拦截器

```javascript
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });
```

**ajax实例添加拦截器**

```javascript
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});

```

**错误处理**

```javascript
axios.get('/user/12345')
  .catch(function (error) {
    if (error.response) {
      // The request was made and the server responded with a status code
      // that falls out of the range of 2xx
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.headers);
    } else if (error.request) {
      // The request was made but no response was received
      // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
      // http.ClientRequest in node.js
      console.log(error.request);
    } else {
      // Something happened in setting up the request that triggered an Error
      console.log('Error', error.message);
    }
    console.log(error.config);
  });
```

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值