web前端学习(一):国内最常用,又优秀的web框架,Vue渐近式框架

一、vue3基础

1.前言

Vue 是一套用于构建用户界面的渐进式框架。开发可以根据需求,逐渐递增所要的方式或者功能模块, vue的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。

vue对项目的侵入性较大,使用者要按照框架所规定的某种特定规范进行开发,项目如果需要更换框架,则需要重新架构整个项目。

2.两大核心

  1. 响应式的数据绑定:当数据发生改变,视图可以自动更新,可以不用关心dom操作,而专心数据操作可组合的视图组件:
  2. 组件式开发: 把视图按照功能切分成若干基本单元,组件可以一级一级组合整个应用形成倒置组件树,可维护,可重用,可测试

1.html页面开发

  ---- css
        <!--通过静态csn资源vue最新版本引入vue模块-->
        <script src="https://unpkg.com/vue@next"></script>
        <style>
            .box{
                color:red;
                background:green;
                display:none;
            }
            div.show{
                display:block
            }
        </style>
    ---- html
        <div id="app">
            <!--1.数据绑定,数据响应式-->
            {{message}}
            <!--2.事件的使用-->
            <!--<h2 @click="show=false">{{title}}</h2>-->
            <!--<h2 @click="show=!show">{{title}}</h2>-->
            <h2 @click="myshow()">{{title}}</h2>
            <!--3.类名和css样式的使用,样式的动态绑定-->
            <!--<div style="background:aqua;" :style="{width:width}">-->
            <!--<div style="background:aqua;" :style="{width,height}">-->
            <div class="box" :class="{show}">
                <ul>
                    <!--4.循环遍历输出数据的值,属性的动态绑定-->
                    <li v-for="item in articles.slice(0,5)" :title="item.content">{{item.title}}</li>
                </ul>
            </div>
        </div>
    ---- js
        <script>
            const app = Vue.createApp({
                data() {
                    return {
                        show:true,
                        width:'300px',
                        height:'500px',
                        message: "this is a test",
                        title: "vue demo" ,
                        articles:[
                            {title:'title111111', content : "content1111"}, 
                        ]
                    }
                },
                methods:{
                    myshow(){
                        this.show=!this.show;
                    }
                }
            }).mount("#app");
        </script>

2.vue-cli脚手架

》Vue-CLI (Command Line Interface)
》Vue-CLI是Vue官方提供的脚手架工具,默认已经帮我们搭建好了一套利用Webpack管理vue的项目结构”
》命令安装: npm install @vue/cli -g           
》检查版本: vue --version
》创建项目: vue create 项目名称
1.创建vue项目
1.创建vue-project项目           
vue create vue-project


2.运行项目
npm run serve (--port=8888)   默认是8080端口

3.打包项目
 npm run build
 

webpack修改默认端口
在package.json中修改脚本配置:"serve": "vue-cli-service serve --port 8888"
 

创建项目流程的其它配置

(1.执行创建命令         vue create vue-project

(2.设置相关插件        一般选择default Vue 3

(3.然后进入项目         cd  项目名称  (上下键选择,空格确认勾选)
     --》sass/scss   --》 Airbnb  --》 >(*) Lint on save  dedicated config files
                                       (*) Lint and fix on commit (requires Git)

   该模板会被计算机保存在计算机所在的用户文件夹下(如:Icy-yun),如果删除vuerc文件,就会删除对应的模板

出现eslint的问题

 
1.webstorm配置
eslint报错,settings --》 搜索eslint --》 选择Eslint package: C:\wamp64\www\vue3\vuedemo\node_modules\eslint
--》 最后在App.vue右键选择Fix Eslint Problems

2.项目配置
eslint 报错, 然后在vue.config.js中添加  
module.exports = {
    ....
    lintOnSave:false
}

2.根目录配置
-- vue.config.js

var webpack = require('webpack'); 
// 注意这一行一定要加上,原本配置中没有,如果不加会导致下面报错webpack未定义
module.exports = {
   //vue-cli3.0 里面的 vue.config.js做配置
    // 开发服务器,跨域使用
    // devServer: {
    //     proxy: {
    //         '/api': {
    //             target: 'http://47.96.133.174:9090',  // 后台接口域名
    //             ws: true,        //如果要代理 websockets,配置这个参数
    //             secure: false,  // 如果是https接口,需要配置这个参数
    //             changeOrigin: true,  //是否跨域
    //             pathRewrite:{
    //               '^/api': '/'
    //             }
    //         }
    //     }
    //   },


    configureWebpack:{
        resolve:{
            alias:{
                'assets':'@/assets',
                'components':'@/components',
                'network':'@/network',
                'utils':'@/utils',
                'views':'@/views',
            }
        },
        plugins:[
            new webpack.ProvidePlugin({
                jQuery: 'jquery',
                $: 'jquery'
            })
        ]
    },
    // 注意:不要添加下面一行,否则路由引入会出现异常
    // publicPath:'./' 
};


 
3.静态资源引入
1.在assets同级目录下的文件,可以直接引入 

(1.main.js中   import 'assets/font/iconfont.css'

(2.App.vue  
  background:url(assets/images/bg-white.png)
  @import("assets/font/iconfont.css") 
 

2.在组件内引入图片, html,和css同理
<img src="~assets/images/logo.png" />

3.组件内引入其它组件 
import HelloWorld from '@/components/HelloWorld.vue'



3.vue模板语法

1.{{}}插值、v-指令

1.基本语法


<p v-once>{[msg}}</p>       数据只第一次时显示,不响应式
<p v-pre>{[msg}}</p>,      内容原封不动的展示, 包含空格,换行
<p v-text='msg'></p>,      就相当于插值表达式的功能
<p v-html='title'></p>,    可以解析标签,  如果有scoped,则不会受到其内部css的影响

data:{
    msg:'test message',
    title:'<h1 style='color:red'>Title</h1>`
}

2.使用实例


    ---- src/App.vue文件内容
    <template>
        <div>
            <h1>{{msg+''+str}}</h1>
            <h1>{{num+1*2}}</h1>
            <h2 v-pre>{{num}}    aa bb   cc  </h2>  <!--v-pre 使用后 没有任何效果-->
            <button @click="num++">button</button>
            <h2 v-once>{{num}}</h2>                <!--v-once 只显示num的初始值-->
            <h2 v-text="num"></h2>                 <!--v-text  h2标签的文本是num值-->
            <h2 v-html="url"></h2>                 <!--v-html 可以解析url的值,就相当于在h2里面添加了一个节点-->
            <h2>{{url}}</h2>
        </div>
    </template>

    <script>
        export default {
            name: 'App',   // 名称
            data() {
                return {
                    msg: 'this is a test',
                    str:' hello vue.js',
                    txt:'hello',
                    num: 0,
                    url:"<a href='https://ww.baidu.com' title='点击查看'>学习猿地</a>",
                }
            },
        }
    </script>

    <style>
    </style>
2.v-bind绑定属性
---- src/App.vue文件内容
<template>
    <div>
        <h2 title="this is a test">{{msg}}</h2>
        <h2 v-bind:title="msg">{{msg}}</h2>                      <!--v-bind是默认存在的绑定关系-->
        <h2 :title="msg">{{msg}}</h2>
        <img :src="imgsrc" :width="100" :height="100" alt="">     <!--使用:冒号则表明当前的属性值是一个变量-->
        <img :src="imgsrc" :width="size" :height="size" alt="">
        <a :href="url">百度一下</a>

        <div :style="'font-size:100px'">Box</div>           <!--绑定style属性-->      <!--字符串形式-->
        <div :style="['font-size:100px','background-color:red']">Box</div>           <!--数组形式-->
        <div :style="[fontsize,bgcolor]">Box</div>                                  <!--数组的变量形式-->

        <div :class="'one two'">One</div>                   <!--绑定class属性-->      <!--字符串形式-->
        <div class="one" :class="['one','two']">One</div>                            <!--数组形式-->
        <div class="" :class="article">One</div>                                    <!--数组的变量形式-->
        <div class="" :class="{one:isone,two:istwo}">One</div>                       <!--json对象形式-->
        <div class="" :class="{three}">One</div>          <!--json对象形式:样式名称与变量名称相同,可以省略键值-->

        <div class="" :class="getStyleArr()">newOne</div>                       <!--方法形式:通过函数获取数组-->
        <div class="" :class="getStyleObj()">newOne</div>                       <!--方法形式:通过函数获取对象-->

    </div>
</template>

<script>
    export default {
        name: 'App',   // 名称
        data() {
            return {
                msg: 'this is a test',
                imgsrc:'https://www.baidu.com/img/flexible/logo/pc/result.png',
                url:"https:www.baidu.com/",
                size:200,
                one:'one',
                two:'two',
                fontsize:'font-size:100px',
                bgcolor:'background-color:green',
                article:['one','two'],
                isone:false,
                istwo:true,
                three:true
            }
        },
        methods:{
            getStyleArr(){
                return [this.one,this.two]          // 必需使用this表明当前对象的变量
            },
            getStyleObj(){
                return {one:this.isone,two:this.istwo}
            }
        }
    }
</script>
 
3.computed计算属性

1.基本语法

》计算属性关键词: computed。
》计算属性在处理一些复杂逻辑时是很有用的。
    computed:{
        site: {
        //getter
        get: function () {
            return this.name +"" + this.url
        },
        // setter
        set: function (newValue) {
            var names = newValue.split(" ")
            this.name = names[0]
            this.url = names[names.length - 1]
        }
    }}

2.使用实例


---- src/App.vue文件内容
    <template>
        <div>
            <h2>{{name}}-{{slogen}}</h2>     <!--多个插值数据连接获取插值数据-->
            <h2>{{name + '-' + slogen}}</h2> <!--连接字符串获取插值数据-->
            <h2>{{getTitle()}}</h2>          <!--methods方法获取插值数据-->
            <h2>{{title}}</h2>               <!--computed计算方法获取插值数据,具有缓冲作用,可以把结果保存在内存中-->

            总价:<small>¥</small>{{books[0].price+books[1].price+books[2].price+books[3].price}}
            总价:<small>¥</small>{{totalPrice}}         <!--computed计算方法使用reduce方法对数据进行求和-->
        </div>
    </template>

    <script>
        export default {
            name: 'App',   // 名称
            data() {
                return {
                    name:'学习猿地',
                    slogen:'成就自己只需一套精品',
                    books:[
                        {id:1,name:'C语言编程',price:10},
                        {id:1,name:'C语言编程',price:20},
                        {id:1,name:'C语言编程',price:30},
                        {id:1,name:'C语言编程',price:40},
                    ]
                }
            },
            computed:{
               title:{
                   set(values){
                       let arr = values.split('-');
                       this.name = arr[0];
                       this.slogen = arr[1];
                   },
                   get(){
                       return this.name+'-'+this.slogen;
                   }
               },
                totalPrice:{
                    get(){
                        return this.books.reduce((s,n)=> s+=n.price,0)   // 使用{},则需要添加return
                    }
                },
            },
            methods:{
                getTitle(){
                    return this.name+'-'+this.slogen;         // 必需使用this表明当前对象的变量
                },
            }
        }
    </script>
 

4.v-on事件监听

1.基本语法

》在前端开发中,需要经常和用户交互
》绑定事件监听器指令: v-on
》缩写:@(语法糖)
》参数: $event
》v-on事件修饰符号
    .stop阻止事件冒泡
    .self 当事件在该元素本身触发时才触发事件
    .capture 添加事件侦听器是,使用事件捕获模式
    .prevent 阻止默认事件
    .once事件只触发一次

2.使用实例


---- src/App.vue文件内容
    <template>
        <div>
            <button v-on:click="num--">-</button>        <!--v-on:和@的使用效果相同,都是监听事件-->
            <input type="text" size="3" v-model="num">    <!--监听事件里面,可以直接使用定义的变量,不需要{{}}-->
            <button @click="num++">+</button>            <!--v-model:可以对input标签内的值进行默认值进行设置-->

            <button v-on:click="sub(100,$event)">-</button>    <!--v-on:和@的使用效果相同,都是监听事件-->
            <input type="text" size="3" v-model="num">       <!--默认不传入参数,如果需要输出传入的值与监听的事件,-->
            <button @click="add()">+</button>                <!--则需要传入值和事件 sub(100,$event)-->

            <!--<div @click="one()" id="box1">
                &lt;!&ndash;<div @click.self="two()" id="box2"> &ndash;&gt;    &lt;!&ndash;.self 当事件在该元素本身触发时才触发事件(连同外层响应)&ndash;&gt;
                <div @click.stop="two()" id="box2">                 &lt;!&ndash;.stop阻止事件冒泡,而不会在点击内层标签的时候,外层标签也响应的情况&ndash;&gt;
                    <button @click.stop="three()">按钮</button>
                </div>
            </div>-->
            <div @click.capture="one()" id="box1">               <!--.capture 添加事件侦听器是,当前添加的标签会优先触发事件,如果内层也有.capture,则从外层向里层依次触发-->
                <div @click.capture="two()" id="box2">
                    <button @click="three()">按钮</button>
                </div>
            </div>

            <a href="https:www.baidu.com/" @click.prevent="demo()">百度一下</a>    <!-- .prevent 阻止当前的默认事件,点击后不会跳转页面-->
            <a href="https:www.baidu.com/" @click.prevent.once="demo()">百度一下</a>    <!-- .prevent和once 阻止一次当前的默认事件,从第二次点击后才会跳转页面-->
        </div>
    </template>

    <script>
        export default {
            name: 'App',   // 名称
            data() {
                return {
                    num: 0,
                    max: 10,
                    min: -5,
                }
            },
            methods: {
                add() {
                    if (this.num >= this.max) {
                        this.num = this.max;
                    } else {
                        this.num++
                    }
                },
                // sub() {
                //     if (this.num <= this.min) {
                //         this.num = this.min;
                //     }else{
                //         this.num--
                //     }
                // }
                // sub(e){                    // 默认当前参数是省略的
                //     console.log(e);         // 输出事件的监听对象
                //     this.num--
                // }
                sub(n, e) {                    // 当前需要传入参数sub(100,$event)
                    console.log(n);         // 输出事件的监听对象
                    console.log(e);         // 输出事件的监听对象
                    this.num--
                },

            }
        }
    </script>
    <style>
        #box1 {
            width: 300px;
            height: 300px;
            background: red;
        }

        #box2 {
            width: 150px;
            height: 150px;
            background: green;
        }

    </style>

5.v-if v-show条件分支

1.基本语法

》 v-if,和v-show
    v-if是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
    v-show就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于CSS进行切换
》v-if v-else
》v-if v-else-if v-else

2.使用实例

    ---- src/App.vue文件内容
    <template>
        <div>
            <button @click="isshow=!isshow">显示/隐藏</button>   <!--isshow=!isshow具有取反的效果-->
            <div v-if="isshow">        <!--当v-if的值是false的时候,当前标签就会清除被替换成“v-if”的一行注释-->
                {{msg}}
            </div>
            <div v-show="isshow">     <!--当v-if的值是false的时候,当前标签就会使用display:none隐藏-->
                {{msg}}
            </div>

            <button @click="isshow=!isshow">显示/隐藏</button>   <!--isshow=!isshow具有取反的效果-->
            <div v-if="isshow">       <!--当v-if的值是false的时候,当前标签就会清除被替换成“v-if”的一行注释-->
                111111111 <br> 
            </div>
            <div v-else>              <!--当v-else的值是v-if的后续-->
                222222222 <br> 
            </div>

            <button @click="card=1">按钮一</button>   <!--card=1具有赋值的效果-->
            <button @click="card=2">按钮二</button>
            <button @click="card=3">按钮三</button>
            <div v-if="card==1">
                111111111 <br> 
            </div>
            <div v-else-if ="card==2">            <!--当v-else-if 的值是v-if的后续-->
                222222222 <br> 
            </div>
            <div v-else-if ="card==3">              <!--当v-else-if 的值是v-if的后续-->
                333333333 <br> 
            </div>
        </div>
    </template>

    <script>
        export default {
            name: 'App',   // 名称
            data() {
                return {
                    msg:'this is a test',
                    isshow:true,
                    card:1,
                }
            },
        }
    </script>     
6.v-for v-key循环遍历

1.基本语法

》遍历指令: v-for
》遍历数组v-for="(item, [index]) in数组”
》遍历对象v-for=" (value,[key], [index]) in对象”
》vue中列表循环需加:key="唯一标识"唯一标识可以是item里面id index等,因为vue组件高度复用增加Key可以标识组件的唯一性,为了更好地区别各个组件 
》key的作用主要是为了高效的更新虚拟DOM,使用diff算法的处理方法,对操作前后的dom树同一层的节点进行对比,一层一层对比

2.使用实例

---- src/App.vue文件内容
<template>
    <div>
        <ul>
            <li v-for="item in list.slice(0,3)" :key="item">{{item}}</li>        
              <!--v-for是循环遍历,vue中列表循环需加:key="唯一标识"唯一标识-->
            <li v-for="(item,index) in list" :key="item">{{index+1}}--{{item}}</li>
            <li v-for="(item,key,index) in obj" :key="item">{{index+1}}--{{item}}</li>
            <li v-for="(item,index) in books" :key="item.id">{{index+1}}--{{item.name}}--{{item.price}}</li>
            <li :class="{active:item.active}" @mouseenter="over(index)" @mouseleave="out(index)" v-for="(item,index) in books" :key="item.id">{{index+1}}--{{item.name}}--{{item.price}}</li>
        </ul>   <!--:class="{active:item.active}"是对象形式-->
    </div>
</template>

<script>
    export default {
        name: 'App',   // 名称
        data() {
            return {
                list:['Java','Python','PHP'],
                obj:{
                    name:"学习猿地",
                    url:"https://www.lmonkey.com"
                },
                books:[
                    {id:1,name:"C语言编和程",price:20,active:false},
                    {id:1,name:"C语言编和程",price:30,active:false},
                    {id:1,name:"C语言编和程",price:40,active:false},
                ]
            }
        },
        methods:{
            over(index){
                for (let i=0;i<this.books.length;i++){
                    if (index===i)
                        this.books[index].active = true;
                    else
                        this.books[i].active = false;
                }
                console.log()
            },
            out(index){
                console.log(index);
            }
        }
    }
</script>
7.v-model双向绑定

1.基本语法

》v-model指令的本质是:它负责监听用户的输入事件,从而更新数据,并对一些极端场景进行一些特殊处理。同时,v-model会忽略所有表单元素的value、checked、selected特性的初始值,它总是将vue实例中的数据作为数据来源。然后当输入事件发生时,实时更新vue实例中的数据。
》实现原理: 
   <input v-bind:value="message" v-on:input="message = $event.target.value" />
》v-model的修饰符号:
  .lazy 懒加载修饰符
  .number修饰符让其转换为number类型
  .trim修饰符可以自动过滤掉输入框的首尾空格
  .keyup.enter 修饰符

2.使用实例

---- src/App.vue文件内容
<template>
    <div>
        <!-- -->
        <input type="text" v-model="msg">
        <br>
        <input type="text" :value="msg" @input="inchange">                <!--:value和v-model使用效果相同 -->
        <input type="text" :value="msg" @input="msg = $event.target.value"><!--:value和v-model使用效果相同 -->
        <br>
        <input type="number" v-model.lazy="msg1">    <!-- .lazy等待输入后,再'enter确认'进行赋值-->
        <input type="number" v-model.number="msg1">  <!-- .number将字符串转换为number类型-->
        <input type="number" v-model.trim="msg1">    <!-- .trim去除首尾空格-->
        {{typeof(msg1)}}

        <label for="one">
            <input type="radio"  id="one" name="sex" value="男" v-model="sex">男     
            <!-- v-model它负责监听用户的输入事件,从而更新数据-->
        </label>
        <label for="two">
            <input type="radio" id="two" name="sex"  value="女"  v-model="sex">女  
            <!-- 当单选框被选中时,v-model里面的值就为value里面的值-->
        </label>
        {{sex}}
        <br>

        <label for="ag">
            <input type="checkbox" id="ag" name="" value="agree" v-model="isAgree">同意协议
            <!-- v-model里面的值为true,则表明复选框被选中-->
        </label>
        <br>

        <label for="a">
            <input type="checkbox" id="a" name="" value="java" v-model="tags">java 
            <!-- v-model里面的会记录当前value里面的值-->
        </label>
        <label for="b">
            <input type="checkbox" id="b" name="" value="python"  v-model="tags">python
        </label>
        <label for="c">
            <input type="checkbox" id="c" name=""  value="php" v-model="tags">php
        </label>
        <label for="d">
            <input type="checkbox" id="d" name=""  value="vue" v-model="tags">vue
        </label>
        {{tags}}

        <select v-model="languages" multiple>  
            <!-- 使用language,则会将选中的数据给language赋值-->
            <option checked value="Java">Java</option>
            <option value="python">python</option>
            <option value="php">php</option>
            <option value="vue">vue</option>
        </select>
        {{language}}
        <br>
    </div>
</template>

<script>
    export default {
        name: 'App',   // 名称
        data() {
            return {
                msg:"this is a test",
                msg1:0,
                sex:'',
                isAgree:true,
                tags:[],
                languages:[]
            }
        },
        methods:{
            inchange(event){
                this.msg = event.target.value;
            }
        }
    }
</script> 

4.vue项目结构

1.组件化开发
》组件化是Vue的精髓,Vue开发就是由一个一个的组件构成的组件的分类:
》页面级组件
    业务上可复用的基础组件
    与业务无关的独立功能组件
》组件开发三要素( prop,自定义事件,slot)
    prop用于定义组件的属性。
    自定义事件用于触发组件的事件。
    slot用于组件功能的扩展。
》组件设计需要考虑的问题
    可扩展性强
    组件中方法函数的抽离,便于复用,适用程度高。
    文档清楚详细
    颗粒度合适,适度抽象
    功能尽可能单一,代码行数适中
2.生命周期函数

1.基本的生命周期

Vue3中组件的生命周期函数, (与data,methods同级)
beforeCreate() {
    console.log("实例刚刚被创建");   
},
created() {
    console.log("实例已经创建完成");
    },
beforeMount() {
    console.log("模板编译之前”);
    }
mounted(){
    console.log("模板编译完成");
},
beforeUpdate(){
    console.log("数据更新之前");
},
updated() {
    console.log("数据更新完成");
},
beforeUnmount(){
    console.log("实例销毁之前");                  
},
unmounted(){
    console.log(“实例销毁完成");
},

2.特殊生命周期


// 特殊的生命周期
activated(){
    console.log("keep-alive缓存的组件激活时调用);   
    使用<keep-alive></keep-alive>标签包含所要监听的内容
},
deactivated({
    console.log('keep-alive缓存的组件停用时调用');
},

3.常用场景


activated(){
    console.log("keep-alive缓存的组件激活时调用);   
    // 使用<keep-alive></keep-alive>标签包含所要监听的内容
    this.$nextTick(()=>{                        
        //等待下一次DOM更新,具有延迟的效果。
        //  调用子组件的方法
        this.$refs.username.abc()             
    })
},
3.slot插槽的应用

1.基本语法

》Vue 实现了一套内容分发的API,这套API的设计灵感源自Web Components规范草案,将<slot>元素作为承载分发内容的出口。
》插槽可以实现组件的扩展性,抽取共性,保留不同
slot     插槽占位
template 向子组件的插槽块添加内容

2.使用实例

---- MyBar.vue文件内容(子组件)
<div class="mybar"> 
    <slot name="one"><span>0000</span></slot> 
    <!--插槽内可以放入默认数据,也可为空-->
    
    <slot name="two">1111</slot>              
    <!--没有name属性的,相比较于有name属性的,就为默认插槽-->
    
    <slot>2222</slot>
    
    <slot name="three" :user="user"></slot>   
    <!--:user="user",可以通过插槽向父组件传入数据-->
</div>



---- MyMain.vue文件内容(父组件)
<my-bar>
    <template v-slot:two> 
    <!--使用指定名称的插槽, -->
    
    <template v-slot:default> 
    <!--使用默认的插槽,一般是没有name属性的插槽或者slot里面没有数据的插槽-->
    
    <!--#one和-v-slot:one使用效果相同,指定插入的位置-->
    <template #one>                         
        <a href="">提交</a>
    </template>
    
    <!--#one和-v-slot:three="subdata"可以通过插槽的方式获取子组件的数据-->
    <template v-slot:three="subdata">         
        <a href="">{{subdata.user.name}}</a>
    </template>
</my-bar>

<my-bar>
    <a href="#">提交</a>        <!--插入数据-->
</my-bar>

<my-bar> </my-bar>             <!-- 不添加数据,则使用插槽内默认数据-->

4.nextTick回调延迟

1.对象方法

this.$nextTick(()=>{    })

this.$nextTick()将回调延迟到下次DOM更新循环之后执行。在修改数据之后立即使用它,然后等待DOM更新,一般放入activated

2.组合式api

import { createApp, nextTick } from 'vue'
// async 异步方法
const changeMessage = async newMessage => {
    message.value = newMessage
    await nextTick()
    console.log('Now DOM is updated')
}
// promise 异步方法
nextTick().then(res=>{
    ....
})
 

5.forceUpdate更新
$forceUpdate

用法:迫使组件实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。

6.watch监听数据
watch:{
	// 监听路由的变化
    $route(to,from){
    	console.log("已经变化了") 
    }
}
7.scoped 样式属性

子组件是被组合到父组件里面,因此父组件是会共享父组件定义的样式,因此只有使用scoped 隔绝样式污染。

<template>
   ...
   
</template>
<script>
    export default {
    name: 'HelloWorld',
    // 通过函数返回一个独立的作用域
    data() {
        return {
            message: 'hello world'
            }
        }
    }
</script>
<style scoped lang="scss">
    /*scoped属性可以限制当前的样式只作用于当前文件 */
    /*lang="scss"可以设置当前的样式是什么类型的文件,应该使用什么语法解析样式*/
</style>

5.父子相互通信

1.props父传子

1.基本语法


// 数组格式接收数据
//props:['msg','title','article'],    

// json格式接收数据,可以不回default缺省值,required:true,需求传入参数
props:{msg:{type:String,default:"#####"},title:{type:String,required:true},article:{type:Array}},

注意点:
  type类型,都是大写的类型 String, Array, Objejct, Boolean

2.使用实例

---- App.vue文件内容(父组件)   
<!-- 父组件传入数据: -->
<my-main msg="hello" :title="msg" :article="article"></my-main>     


---- MyMain.vue文件内容(子组件)
<template>
    <my-conn></my-conn>
    <my-conn></my-conn>
    {{msg}}
    {{show()}}
    {{title}}
    {{article}}
    <span v-for="item in article">{{item}}</span>
</template>

<script>
    import MyConn from "./childsComp/MyConn"
    export default {
        name: "MyMain",                      
        // 数组格式接收数据
        //props:['msg','title','article'],    
        
        // json格式接收数据,可以不回default缺省值,required:true,需求传入参数
        props:{msg:{type:String,default:"#####"},title:{type:String,required:true},article:{type:Array}},
        components:{           
            MyConn                
        },
        data(){
            return {
                msg1:'world'
            }
        },
        methods:{
            show(){
                return this.msg + this.msg1
            }
        }
    }
</script>
 
2.$emit子传父

1.基本语法

子组件向父组件派发一个自定义事件, 并向这个事件传入实参 

父组件的自定义事件被触发,则会收到传递的实参。

2.使用实例

---- MyConn.vue文件内容(子组件)
<button @click="changenum(2)">+</button>    触发事件
methods:{
    changenum(num){
        this.$emit('mycountevent',num);     
        <!-- 传递触发事件 -->
    }
}

---- MyMain.vue文件内容(父组件)
<my-conn @mycountevent="mydemo"></my-conn>       
 <!-- 接收子组件传递的触发事件 -->
methods:{
    mydemo(data){
        this.count += data;                        
        <!-- 接收数据 -->
    }
}

3. p a r e n t 和 parent和 parentroot父节点

子组件获取父组件的属性与方法


---- App.vue文件内容(根组件)
    appmet(){
        console.log('我是APP Root组件中的appmet方法')
    }


---- MyMain.vue文件内容(父组件)
    changen(){
        this.count++;
        console.log('这是组件MyMain中的changen方法');
    },
    
    
---- MyConn.vue文件内容(子组件)
    <button @click="one()">++</button>            触发事件
    one(){
        console.log('这是子组件MyConn中的one方法');
        this.$parent.changen();                    获取父组件的属性与方法
        this.$parent.$parent.appmet();             获取级祖父组件的属性与方法
        this.$root.appmet();                       获取根组件的属性与方法
    },

4. r e f s . x 和 refs.x和 refs.xemit子节点

父组件获取子组件的属性与方法

1.基本语法


<my-conn ref="aaa" @mycountevent="mydemo"></my-conn>         取别名,确定子组件的属性 
this.$refs.aaa.changeone();                                  获取子组件的方法
let num = this.$refs.aaa.num;                                获取子组件的属性

2.使用实例

---- MyConn.vue文件内容(子组件)
    <button @click="changenum(2)">+</button>          子组件触发事件

    changenum(num){
        this.$emit('mycountevent',num);               向父组件传递事件
    }, 


---- MyMain.vue文件内容(父组件) 
    <button @click="two()">子组件加1</button>                     触发事件 
    <my-conn ref="aaa" @mycountevent="mydemo"></my-conn>         取别名,确定子组件的属性 <!--ref="one"取别名-->

    mydemo(data){                                                接收数据
        this.count += data;
    },
    two(){ 
        this.$refs.aaa.changeone();                               获取子组件的属性与方法
        let num = this.$refs.aaa.num;                      
    }

6.axios请求数据

安装模块


》在该项目下安装axios     npm install axios -S
》打开wampserver服务
1.axios 的get方法
  
axios.get('http://localhost/axiosdemo/getapi.php?id=1&name=小明') .then(res=>{
    console.log(res);
    this.links = res.data;
    console.log(typeof(res.data))
}).catch(err=>{
    console.log(err);
}) 

2.axios 的post方法

axios.post('url',data,{ 
    transformRequest:[          // 将数组格式转化成字符串
        function(data) {
            let ret = "";
            for (let it in data) {
                ret+=  encodeURIComponent(it) +"="+  encodeURIComponent(data[it])+"&";
            }
            return ret;
        }
    ],
    headers: {
        "Montent-Type" : "application/x-www-form-urlencoded"
    }
}).then(res=>{
    console.log(res);
}).catch(err=>{
    console.log(err);
});
3.封装网络请求
import axios from 'axios';

// 方法一:封装成函数
function request(config){

    //使用axios创建一个实例对象
    const instance = axios.create({
        baseURL: 'http://api.eduwork.cn/admin',                   // 基本的url
        timeout: 5000,                                            // 超时限制
    });
    
    //请求拦截器
    instance.interceptors.request.use( config=>{
        //config.headers.token = "123456"      // 可以在修改数据后,再返回
        return config;
    },  err =>{
        return Promise.reject(err);            // 返回出错信息
    });
    
    //响应拦截器
    instance.interceptors.response.use( response =>{
        console.log(response);
        return response;
    }, err =>{
        return Promise.reject(err);           // 返回出错信息
    });
    
    return instance(config);  
}


// 方法二:封装成方法 
function http(){ 
    //使用axios创建一个实例对象
    const instance = axios.create({
        baseURL: 'http://api.eduwork.cn/admin',                   // 基本的url
        timeout: 5000,                                            // 超时限制
    });
    
    instance.interceptors.request.use( config=>{
        //config.headers.token = "123456"      // 可以在修改数据后,再返回
        return config;
    },  err =>{
        return Promise.reject(err);            // 返回出错信息
    });
    return {
        //get请求
        get(url,params){               // params是一个json对象
            return instance.get(url,{
                params
            })
        },
        //post请求
        post(url,data){
            return instance.post(url,data,{      // data是一个数组,包含多个json对象
                transformRequest:[                  // transformRequest是将一个数组,改变成字符串
                    function(data){
                        let str = "";
                        for(let key in data){
                            str += encodeURIComponent(key)+"=' +encodeURIComponent(data[key])+ '&';
                        }
                        console.log(str);
                        return str;
                    }
                ],
                headers: {
                    "Content-Type": "application/x-www-form-urlencoded"
                }
            })
        },
        //delete请求
        delete(url){
            return instance.delete(url)
        }
    } 
}

7.vue-Router路由

1.Router路由模式

1.基本知识

延迟加载动态导入和路由模式解析
》路由是由多个URL组成的,使用不同的URL可以相应的导航到不同的位置
》Vue-Router在切换页面时是没有重新进行请求的,使用起来就好像页面是有状态的一样,借助了浏览器的History APl来实现的,这样可以使得页面跳转而不刷新,页面的状态就被维持在浏览器中
》vue-router中默认使用的是hash模式,也就是会出现URL中带有#号
》有三种模式
    .Hash:使用URL的hash值来作为路由,用来指导浏览器动作的,对服务器端完全无用,支持所有浏览器
    .History: 以来HTML5 History API和服务器配置。
    .Abstract:支持所有javascript运行模式。如果发现没有浏览器的API,路由会自动强制进入这个模式。

2.使用实例

 ----./src/router/index.js文件内容(创建路由)
    import { createRouter, createWebHistory } from 'vue-router'
    import Home from '../views/Home.vue'

    const routes = [
        {
            path: '/',               // 路径
            name: 'Home',            // 名称
            component: Home          // 组件    引入方式一
        },
        {
            path: '/about',
            name: 'About', 
            component: () => import('../views/About.vue') // 引入方式二
        }
    ]; 
    const router = createRouter({      // 创建路由 
        //history: createWebHistory(process.env.BASE_URL),       // 历史记录
        history: createWebHashHistory(process.env.BASE_URL),       // 历史记录,url会有#号出现, 默认
        routes                                                 //路由规则
    });
    export default router                      //暴露路由


----./src/main.js文件内容(配置路由)
    import { createApp } from 'vue'
    import App from './App.vue'
    import router from './router'                         // 添加路由文件
    createApp(App).use(router).mount('#app')               // 配置路由


----./src/App.vue文件内容(使用路由)
    <div id="nav">
        <router-link to="/">Home</router-link>   // 页面上指向路由的接口
        <router-link to="/about">About</router-link>
    </div>
    <router-view/>                          // 加载的数据放置的位置

3.懒加载,空页匹配

const home = ()=>import("../xxxx")


path:"/:pathMatch(.*)"      // vue3

4.rooter-link路由跳转
 
----./src/App.vue文件内容(使用路由)
<div id="nav">
    <!-- active-class 活动类名 -->
    <router-link active-class="active" to="/">Home</router-link> 
    <router-link to="/about">About</router-link>  
    <!--添加一个页面-->
    <button @click="$router.push('/about')">个人中心</button>
    <!--返回上一个页面-->
    <button @click="$router.go(-1)">返回</button> 
     <!--当前路径-->
    {{$route.path}}                                              
</div>


<!-- 显示加载的路由 -->
<router-view/>


<!--加载默认路由-->
<router-view class="one" name="About"></router-view>           
<router-view class="two"></router-view>                  
<router-view class="three" name="Home"></router-view>

5.children嵌套子路由

1.基本语法


单独的路由规则 ,不能直接设置为多级路由。

2.使用实例


let MyOrder = () => import('../views/MyOrder.vue');
let MySetting = () => import('../views/MySetting.vue');
{
    path: '/about',
    name: 'About',            // name只用于router-view的name属性
    component:About,
    children: [                        //创建子路由
        {
            path:'',
            component: MySetting       //默认显示的子路由
        },
        {
            path: 'order',     // about/order
            component: MyOrder
        },
        {
            path: 'setting',     // about/setting
            component: MySetting
        }, 
    ]
}

6.path和query参数传递

1.基本语法


》传递参数主要有两种类型: params和query”params的类型:

》params的类型:
    配置路由格式: /user/:id (动态路由)
    传递的方式:在path后面对应的值:to=” '/user /' +uid"
    传递后形成的路径: /usei/9,/user/zs
    接收参数:$route.params.id

》query的类型:
    配置路由格式: /user,正常配置
    传递的方式: 对象中使用query的key作为传递方式:to= {path:' /' , query:lid:1,name:'abc'l}
    传递后形成的路径:/user?id=9,/user?id=zs
    接收参数: $route.query.name 

2.使用实例


 
---- src/views/About.vue文件内容
<ul>
<!--1.使用路由方式一-->
    <li><router-link :to='"/about/page/"+items.id'>{{items.title}}</router-link></li>
    <li> <router-link to="/about/article?name=111&age=10">文章一</router-link></li>
    
    <!--2.使用路由方式二-->
    <li> <router-link :to="{path:'/about/article',query:{name:'hello',age:100}}">文章二</router-link></li>
    
    <!--3.使用路由方式三-->
    <li><button @click="$router.push({path:'/about/article',query:{name:'hello',age:100}})">文章三</button></li>
</ul>

---- src/router/index.js文件内容
{
    path: '/about',
    name: 'About',            // name只用于router-view的name属性
    component: About,
    children: [                        //创建子路由
        {
            path:'',
            component: MySetting       //默认显示的子路由
        },
        {
            path: 'order',     // about/order
            component: MyOrder
        },
        {
            path: 'setting',     // about/setting
            component: MySetting
        },
        {                       // about/page/11
            path:'page/:id',        // 一定要添加:号
            component: MyPage
        },
        {                       // about/article?name=hello&age=100
            path:'article',
            component: MyArticle
        }
    ]
}

---- src/views/MyPage.vue文件内容
    <h2>这是文章的模板</h2>
    文章ID:{{$route.params.id}}           <!--获取参数-->

---- src/views/MyArticle.vue文件内容
    <h2>这是文章的页面:</h2>
    name:{{$route.query.name}}<br>        <!--获取参数-->
    age:{{$route.query.age}}

7.redirect重定项和alias别名

               》重定项:
                    重定向也在routes配置中完成,要从重定向/a到b
                    const routes = [{ path: '/home', redirect: '/' }]
                    const routes = [ path: "/home' , redirect: { name: 'homepage' } }]
                    path: '/search/:searchText',
                    redirect: to =>{
                        return { path: '/search', query: { q: to.params.searchText } }
                        ),
                》别名:
                    别名/as/home表示用户访问时/home,URL保持不变/home,但将被匹配,就像用户正在访问时一样/。
                    const routes = [{ path: '/' , component: Homepage, alias: "/home"}]
                    alias: ['people', 'list']
                    alias: ['/:id' , '']

                 ---- src/router/index.js文件内容
                    const routes = [
                        {
                            path: '/',               // 路径
                            name: 'Home',            // 名称
                            component: Home          // 组件
                            /*components:{                // 多个路由组成的组件
                              default:Home,          // 默认页面
                              About
                            }*/
                        },
                        {
                            path: '/home',               // 路径
                            name: 'RedirectHome',                     // 名称
                            redirect:{name:'Home'},                   // 重定向
                            alias:['a','b','c'],                      // 取别名
                            component: Home          // 组件
                        },
                        {
                            path: '/about',
                            name: 'About',            // name只用于router-view的name属性
                            component: About,
                            children: [                        //创建子路由
                                {
                                    path:'',
                                    component: MySetting       //默认显示的子路由
                                },
                                {
                                    path: 'order',     // about/order
                                    component: MyOrder
                                },
                                {
                                    path: 'setting',     // about/setting
                                    component: MySetting
                                },
                                {                       // about/page/11
                                    path:'page/:id',        // 一定要添加:号
                                    // ** path子路由重定向query子路由(无法反过来)
                                    // $route = to
                                    redirect :to => {
                                        return {path: 'article', query: {name: 'zhangsan', age: to.params.id}};
                                    },
                                    // ** 取别名
                                    alias:['p/:id','x/:id'],
                                    component: MyPage
                                },
                                {                       // about/article?name=hello&age=100
                                    path:'article',
                                    component: MyArticle
                                }
                            ]
                        }
                    ];
8.beforeEach导航守卫

1.基本语法

》导航守卫主要用来通过跳转或取消的方式守卫导航。
》前置守卫
    // to: Route:即将要进入的目标路由对象,
    // from: Route:当前导航正要离开的路由
    // next: 将要跳转的页面
    router.beforeEach((to, from,next)=>{
        return false
    })
》后置钩子
	router.afterEach((to, from) =>{
        return false
	})
》有多种机会植入路由导航过程中:全局的,单个路由独享的,或者组件级的。
    1.全局导航守卫
    2.路由独享的守卫
    3.组件内的守卫(设置标题或者失败跳转)

2.使用实例

 
// 1.路由独享守卫
---- src/router/index.js文件内容
{
    path: '/',               // 路径
    name: 'Home',            // 名称
    component: Home,          // 组件
    meta: {
        title: '222222'     // 元数据,可以通过全局的前置守卫,设置标题
    },
    beforeEnter: (to, from) => {         // 路由独享的守卫(局部)
        return false;
    },
    /*components:{                // 多个路由组成的组件
        default:Home,          // 默认页面
        About
    }*/
},


//  2.全局守卫
// 前置守卫(全局)
router.beforeEach((to, from) => {    // 与const router = createRouter  同级
    // return false                       // next已经被取消, false 表示禁用跳转,true表示放行
    console.log(to.fullPath);
    console.log(from.fullPath);
    document.title = to.meta.title;       // 通过元数据,来设置标题
}); 
// 后置勾子(全局)
router.afterEach((to, from) => {    // 与const router = createRouter  同级
    // return false                       // next已经被取消, false 表示禁用跳转,true表示放行
    console.log('----' + to.fullPath);
    console.log('----' + from.fullPath);
});


// 3.组件内部路由守卫(路由函数)
---- src/views/Home.vue文件内容 
beforeRouteEnter(to,from,next){ 
    document.title = "主页";       // 设置标题
    next(vm => {       })           // 组件内的守卫,与components同级
}
beforeRouteLeave(to,from,next){
    next(vm => {       })
}
9.keep-alive和vue-router

1.基本语法


》keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
    include:正则表达式,exclude: 正则表达式
》router-view是vue-router内置组件,如果直接包含在keep-alive里面,所有路径匹配到的组件都会被缓存。

// 1.完整的缓存标签
<!--保持组件创建的状态,而不会被销毁-->
<router-view v-slot="{Component}">
    <transition>
    <!-- 排除需要缓存的网页 -->
    <!--<keep-alive exclude="About,Home">;-->
    <!-- 下面是缓存所有组件 -->
        <keep-alive>
            <component :is="Component"/>
        </keep-alive>
    </transition>
</router-view>


// 2.选择性显示
// 目标路由定义: meta: {keepAlive: true} // 这个是需要keepalive的
<keep-alive>                          
    <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
 

2.使用实例

activated(){
    console.log('keep-alive缓存的组件激活时调用 ');
    this.$router.push(this.path);
},
deactivated(){
	console.log('keep-alive缓存的组件停用时调用 ');
},
10.currentRoute当前路由

可以直接在页面上输出。
{{$route}}      //    $route表示当前路径的路由
{{$router}}      //    $route表示当前路径的路由


// 1.对象式api
this.$router.currentRoute      当前路由对象
this.$router.currentRoute._value    当前路由参数
{
     fullPath: "/tablist/detail?scene_id=110"
     hash: ""
     href: "/tablist/detail?scene_id=110"
     meta:{ 
        title: "景区详情" 
     }
     name: "detail"
     params: {}
     path: "/tablist/detail"
}


// 2.组合式api,
route = useRoute()
{
     fullPath: "/tablist/detail?scene_id=110"
     hash: ""
     href: "/tablist/detail?scene_id=110"
     meta:{ 
        title: "景区详情" 
     }
     name: "detail"
     params: {}
     path: "/tablist/detail"
}

8.vuex状态管理

Action -> State -> View -> Action ->… 循环


》Vuex是一个专为Vue.js应用程序开发的状态管理模式。
    .就是一个加强版的data!在单页应用中会有一个data函数,管理当前应用的状态。处理大量的需要在组件间传递的数据,直接定义一个全局的data属性保存就行了。
    .如果我们的页面比较简单,切记千万不要没事找事引入Vuex,我们使用Vuex是因为项目变得复杂之后,有很多数据需要在父组件、子组件和孙组件之间传递,
    处理起来很繁琐,于是就需要Vuex这样一个可以对这一部分数据进行统一管理的东西。
    .也是响应式
》什么情况需要使用Vuex管理状态在多个组件间共享?
    大型项目中组件很多,多个组件中共用的数据
    例如:用户的登录状态、用户名称、头像、地理位置信息等
    例如:商品的收藏、购物车中的物品。
1.$store.state.xxx的状态

(注意router使用的$route)

1.基本结构

    import { createStore } from 'vuex'
    export default createStore({
        state: {
            num:0
        },
        mutations: {
        },
        actions: {
        },
        modules: {
        }
    })

2.使用实例

---- src/Contents/HelloWorld.vue文件内容
    <template>
        <div class="hello">
        <h1>在子组件helloworld中应用Home中的Data</h1>
        {{count}}                         <!--获取父组件的数据-->

        <h2>在HelloWorld组中使用全局的状态</h2>
        <h2>{{$store.state.num}}</h2>       <!--使用全局变量-->
        </div>
    </template>


---- src/views/Home.vue文件内容
    <div class="home">
        <h2>这是在单页模板中应用</h2>
        <button @click="count--">-</button>
        <button @click="count++">+</button>

        <!--父组件向子组件传递信息-->
        <HelloWorld :count="count"/>

        <h2>使用全局的状态</h2>
        <h2>{{$store.state.num}}</h2>
        <button @click="$store.state.num--">-</button>
        <button @click="$store.state.num++">+</button>
        <!--通过事件的方式改变全局的状态-->
    </div>

2.$store.commit提交同步

1.Mutations同步操作


---- src/store/index.js文件内容
    import {createStore} from 'vuex'

    export default createStore({
        state: {
            num: 0,
            dnum: 0
        },
        mutations: {              // 可以通过devtools工具查看状态管理
            sub(state) {
                state.dnum--;
            },
            add(state) {
                state.dnum++;
            },
            sub2(state,count) {         // 传入一个参数
                state.dnum-= count;
            },
            add2(state,count) {
                state.dnum+= count;
            },
            sub3(state,payload) {      // 传入多个参数(普通方式)
                state.dnum-= (payload.count+payload.num);
            },
            add3(state,payload) {
                state.dnum+= (payload.count+payload.num);
            },
            sub4(state,p) {           // 传入多个参数(对象方式)
                state.dnum-= (p.payload.count+p.payload.num);
            },
            add4(state,p) {
                state.dnum+= (p.payload.count+p.payload.num);
            },
        },
        actions: {},
        modules: {}
    })

**2.组件调用 **

    ---- src/views/Home.vue文件内容
    <h2>使用Mutations来修改状态</h2>
    <h2>DNUM:{{$store.state.dnum}}</h2>
    <button @click="$store.state.num--">-</button>
    <button @click="$store.state.num++">+</button>
    <br>
    <h2>使用Mutation来修改状态,带一个参数</h2>
    <button @click="sub2()">-</button>
    <button @click="add2()">+</button>
    <br>
    <h2>使用Mutation来修改状态,带多个参数</h2>
    <button @click="sub3()">-</button>
    <button @click="add3()">+</button>
    <br>
    <button @click="sub4()">-</button>
    <button @click="add4()">+</button>
    <!--通过事件的方式改变全局的状态-->

    methods:{
        add1(){
            this.$store.commit('add');
        },
        sub1(){
            this.$store.commit('sub');
        },
        add2(){                                // 使用带一个参数
            let count = 2;
            this.$store.commit('add2',count);
        },
        sub2(){
            let count = 2;
            this.$store.commit('sub2',count);
        },
        add3(){                                 // 使用带多个参数
            let count = 2;
            let num=1;
            const payload = {                // 必需使用对像的方式传入多个参数
                count,num
            };
            this.$store.commit('add3',payload);  // 普通方式
        },
        sub3(){
            let count = 2;
            let num=1;
            const payload = {
                count,num
            };
            this.$store.commit('sub3',payload);
        },
        add4(){                                 // 使用带多个参数
            let count = 2;
            let num=1;
            const payload = {                // 必需使用对像的方式传入多个参数
                count,num
            };
            this.$store.commit({             // 使用对象的方式传递
                type:'add4',
                payload
            });
        },
        sub4(){
            let count = 2;
            let num=1;
            const payload = {
                count,num
            };
            this.$store.commit({
                type:'sub4',
                payload
            });
        },
    }

4.$store.getters.xxx获取数据

---- src/views/Home.vue文件内容
    <h2>使用getter中的计算属性:{{$store.getters.vxnum}}</h2>
    <h2>购物车的总价:{{$store.getters.totalprice}}</h2>
    <h2>贵重物品的总价:{{$store.getters.specialtotalprice}}</h2>
    <h2>贵重物品(self)的总价:{{$store.getters.specialtotalpriceself(10)}}</h2>
    <!--因为不是正常使用的方法,所以不能加括号-->


---- src/store/index.js文件内容
    import {createStore} from 'vuex'
    export default createStore({
    state: {
        num: 0,
        dnum: 0,
        cartlist: [
            {name:'《细说PHP》',price:10},
            {name:'《细说PHP》',price:20},
            {name:'《细说PHP》',price:30},
            {name:'《细说PHP》',price:40},
        ]
    },
    getters:{              // 与mutations,state同级
        // 第一个参数就是state
        vxnum(state){
            return Math.pow(state.num,2);
        },
        totalprice(state){
            return state.cartlist.reduce((s,n) => s+n.price,0);
        },
        goodsgt(state){                      // 这里返回的是数组中的元素
            return state.cartlist.filter(n => n.price>20);
        },
        specialtotalprice(state,getters){      // 以getters中所有的变量作为参数
            return getters.goodsgt.reduce((s,n)=>s+n.price,0)
        },
        goodsself(state){                                  // 返回一个方法,作为回调函数
            return (price)=>state.cartlist.filter(n => n.price>price);
        },
        specialtotalpriceself(state,getters){              // 因此,可以通过返回一个回调函数,向getters中传递参数
            return function(price){
                return getters.goodsself(price).reduce((s,n)=>s+n.price,0)
            }
        }

    },
    mutations: {              // 可以通过devtools工具查看状态管理
        ...
    },
    actions: {},
    modules: {}
    })  
5.$store.dispatch派发异步

派发异步操作

 ---- src/views/Home.vue文件内容
    <h2>使用action改变状态</h2>
    <button @click="cnum()">不传递参数Action</button>
    <button @click="cnum(80)">传递参数Action2(80)</button>
    <!--使用默认参数时,一定要添加括号,如果没有参数,则可以省略-->

    methods:{
        cnum( params=null){
            if (params ===null)
                this.$store.dispatch('demo');  // 分发数据
            else
                this.$store.dispatch('demo2',params);  // 分发数据
        },
    }


---- src/store/index.js文件内容
    import {createStore} from 'vuex'
    export default createStore({
        state: {},
        getters:{},
        mutations: {      
            cnum(state,params=null){
                if(params==null)
                    state.num = 99;
                else
                    state.num = params;
            }
        },
        actions: {                    // 与state,getters,mutations同级
            demo(context){
                setTimeout(()=>{
                     // context.state.num = 99;
                    context.commit('cnum');                 // 通过mutations改变状态
                },300)
            },
            demo2({state,commit,getters},payload){      // 这个效果同上,其实是context只是一个对象,包含所列的所有属性
                setTimeout(()=>{
                    state.num = payload;
                    commit('cnum',payload);               // payload也可以是一个对象
                },300)
            },
            actionA({commit}){
                return new Promise((resolve, reject) =>{
                    setTimeout(()=>{
                        commit('someMutation');
                        resolve()
                    },1000)
                })
            },
            actionB({dispatch,commit}){
                return dispatch('actionA').then(()=>{
                    commit('someOtherMutation')
                })
            }
        },
        modules: {}
    })

6.moduls模块划分
---- src/store/index.js文件内容
    import {createStore} from 'vuex'

    // 模块划分
    const user={
        state:{
            name:"xiaoming",
            id:'0101'
        },
        getters:{
            // 返回当前对象的数据
            fullname(state){
                return state.name + state.id;
            },
            // 调用当前对象的getters
            fullname2(state,getters){
                return getters.fullname + '22222';
            },
            // 调用全局的state,调用全局的getters没有必要,不过在actions中可以通过rootGtters获取全局的getters
            fullname3(state,getters,rootState){          // rootState表示根对象的状态
                return getters.fullname + rootState.num;
            }
        },
        mutations:{
            setname(state,payload){
                state.name = payload;
            }
        },
        actions:{
            dosome({state,commit}){            // context中包含所有可用的属性,包含父类的rootState,rootGetters
                setTimeout(()=>{
                    commit('setname','hello vuex');
                },2000)
            }
        },
    };
    const article={};
    const cart={};
    const goods={};



    // 文件划分,
    // 》划分state 可以设置常量
    // 》划分getters,mutations,actions,子模块
    //   1.把getters中的对象(因为省略了键名)保存在js文件中,使用export default{}  暴露
    //   2.使用import getters from './getters' 引入文件

    export default createStore({
        state: { },
        getters:{ },
        mutations: { },
        actions: { },
        modules: {
            user,
            article,
            cart,
            goods
        }
    })

9.组合式API (Vue3)

》使用传统的option配置方法写组件的时候问题,随着业务复杂度越来越高,代码量会不断的加大;
  由于相关业务的代码需要遵循option的配置写到特定的区域,导致后续维护非常的复杂,
  同时代码可复用性不高,而composition-api就是为了解决这个问题而生的。

》Composition API字面意思是组合API,它是为了实现基于函数的逻辑复用机制而产生的。主要思想是,我们将它们定义为从新的setup函数返回的JavaScript变量,而不是将组件的功能(例如state.method、computed等)定义为对象属性。

》setup函数在创建组件之前被调用,所以在setup被执行时,组件实例并没有被创建。因此在setup函数中,我们将没有办法获取到this。

》接收context是setup()的第二个参数是一个上下文对象,这个上下文对象大致包含了这些属性,
注意:在setup()函数中无法访问this
const MyComponent = {
    setup(props, context) {
            context.attrs
            context.slots
            context.parent
            context.root
            context.emit
            context.refs   // 没有refs
    }
}
1.setup函数组合
  ---- src/views/About.vue文件内容(组合api)
    <template>
    <div class="about">
        <h3>count:{{data.count}}</h3>
        <h3>double:{{data.double}}</h3>
        <h3><button @click="add">增加</button></h3>
    </div>
    </template>
    <script>
    import {reactive,computed} from 'vue';
    export default {
        setup(){                        // setup的值是一个函数,而不是作为一个对象
            const data = reactive({
            count:0,
            double:computed(()=>{return data.count*2})
            });
            function add(){
            data.count++
            }
            return {data,add}
        }
    }
    </script>
2.props, ref, onMounted

1.基本语法

》setup()函数是vue3中专门新增的方法,可以理解为Composition Api的入口.
》执行时机在beforecreate之后,created之前执行. 调用时机, this指向,函数参数,返回值
》接收props数据, ref 进行绑定标签


2.使用实例


// 1.组合式api中的ref
    <template>
      <div class="home" ref='root'>
          我是hme元素
      </div>
    </template>
    <script>
      import {ref,onMounted} from 'vue';
      export default {
        setup(){
          const root = ref(null);
          onMounted(()=>{
            console.log(root.value)    // <div class="home"> 我是hme元素 </div>
          })
          return { root }
        }
      }
    </script>

// 2.组合式api中的ref
    <script>
    export default {
        name: "SubComp",
        props: {
            one: {
                type: String,
            },
            two: {
                type: String,
            }
        },
        setup(props,context){          // context 也可以使用解构赋值的方式,{attrs,slots,emit}
            // 在创建对象之前调用,所以没有this
            // props 是父组件传递的属性
            // context是上下文(传递后没有接收的)
            console.log('setup()....');
            console.log(props.one+','+props.two);
            console.log(context.attrs.desc);
            console.log(context.slots.default());
            context.emit('myadd','向父组件传入数据')        // 向父组件传入数据
        },
        beforeCreate(){
            console.log('beforeCreate()....')
        },
        created(){
            console.log('created()....')
        }
    }
    </script>
3.ref,reactive,toRefs组合式

1.基本语法

》ref()函数用来给定的值创建一个响应式的数据对象,ref()的返回值是一个对象,这个对象上只包含一个.value属性.
》reactive是用来创建一个响应式对象
》将ref响应式数据挂载到reactive中,当把ref()创建出来值直接挂载到reactive()中时,会自动把响应式数据对象的展开为原始的值,不需要通过.value就可以直接访问到

》双向绑定
》toRefs()解构响应式对象
》readonly将响应式数据变回原使数据


// reactive的对象 ,需要使用toRefs拆开暴露 , 并且初始化时需要定义直接子元素,不然即使对象 被赋值 也无法获取到新的数据, 
// 如 1.settings = reactive({}), 并且使用  params = {xxxx},则settings的 数据会一直是空
//    2.赋值 params.name = "3333",params[xxx] = 'xxx'则有效, 无论初始值是否为空。
// toRefs是对reactive的解析作用。 而对象属性的变化不会触发页面的更新 。
// v-model不能绑定reactive创建的对象的子元素,而使用data返回的参数就可以。(element-ui的表单限制)

// 赋值reactive对象(直接赋值对象,无效)
const setReactive = (obj,newobj)=> {
    Object.keys(newobj).forEach(item=>{
    	obj[item] = newobj[item]
    })
}


2.使用实例

---- src/views/ComApi.vue文件内容
    <template>
        <div>
            <h2>常用api应用</h2>
            原生的:{{num}} <br>
            <!--调用方法:{{myfun()}} <br>-->
            ref的变量:{{num2}} <br>
            <!--ref调用方法:{{myfun2(55)}} <br>-->
            <!--reactive中的对象:{{user.name}}、{{user.age}}-->
            reactive中的对象2:{{name}}、{{age}} <br>
            <!--注意:这个绑定前需要提前使用变量-->
            isRef的变量:{{num3}} <br>

            <br>
            num2 <input type="text" v-model="num2">
            <br>
            <!--通过普通的方式显示user中的变量-->
            <!--user.name <input type="text" v-model="user.name"> <br>-->
            <!--user.age <input type="text" v-model="user.age"> <br>-->
            <br>
            user.name <input type="text" v-model="name"> <br>
            user.age <input type="text" v-model="age"> <br>
        </div>
    </template>

    <script>
        import {ref,reactive,toRefs,readonly,isRef} from 'vue';
        export default {
            name: "ComApi",
            data(){
                return {}
            },
            setup(){
                let num=1;
                let myfun = ()=>{            // 数据不是响应式的
                    num++;
                    console.log(num);
                };
                let num2 = ref(2);            // 这个num2已经变成一个对象(响应式)
                let myfun2 = (newvalue)=>{
                    num2.value = newvalue;
                    console.log(num2.value)
                };
                let user = reactive({          // 创建一个reactive对象(响应式)
                    name:"lmonkey",
                    age:28,
                    sex:'男',
                    num2            // 在reactive中,可以不需要使用value属性
                });
                // let user2 = readonly(user);                       // readonly切换成不是响应式的对象,
                let num3 = isRef(num2) ? num2.value = 44 : num2 = 55;    
                // isRef(num2) 判断当前对象是否是响应式对象

                                     // 将对象拆成单独的变量,...是让对象的变量展开,而toRefs是响应式变化
                return {num,myfun,num2,myfun2,...toRefs(user),num3}     //或者直接使用user
            }
        }
    </script>
4.useRouter,useRoute路由

1.基本知识

》setup和Vue的Composition API的引入,开辟了新的可能性,但为了能够充分利用Vue Router的潜力,我们将需要使用一些新功能来替换对访问this和组件内导航保护的使用。
》由于我们无权访问setup的内部this,因此无法直接访问this.$router或this.$route了,相反,我们使用useRouter和useRoute函数。
》请注意,我们仍然可以访问$router和$route在模板中,因此无需在router或之route内返回setup.
》尽管您仍可以将组件内导航保护与setup功能结合使用,但Vue Router会将更新和离开提供Composition&API函数:
  1.onBeforeRouteLeave((to, from) =>{})
  2.onBeforeRouteUpdate(async (to, from)=>{})

2.使用实例

 
<script>
    import {useRoute,useRouter,onBeforeRouteLeave} from 'vue-router';
    import {watch,ref} from "vue";
    export default {
        name: "MyPage.vue",
        setup(){
            const route = useRoute();
            const router = useRouter();
            let id = ref();

            watch(()=>route.params,(newid)=>{    // 通过watch监听数据的改变
                id.value = newid.id 
            });
            
            const jumpPage = ()=>{
                router.push({path:'/routerapi/article',query:{name:'aaaa',keyword:'1111'}});
            }           

            onBeforeRouteLeave((to,from)=>{
                let isok = window.confirm(`你确定要从${from.fullPath}到${to.fullPath}`);
                if(!isok)
                    return false
            });

            return {id}
        },  
    }
</script>

5.useStore状态管理
 <script>
    import {useStore} from 'vuex';
    import {computed} from 'vue';
    export default {
        name: "VuexApi",
        setup(){
            const store = useStore();
            return {
                num2:computed(()=>store.state.num2),
                double2:computed(()=>store.getters.double2),
                cnum2:(newnum)=>{store.commit('changenum2',newnum)},
                canum2:( )=>{store.dispatch('timecnum2')},
            }
        }, 
    }
</script>
 
6.compouted计算属性

》computed()用来创建计算属性,返回值是一个ref的实例。

---- src/views/ComputedDemo.vue文件内容
    <template>
        <h2>计算属性</h2>
        firstname: <input type="text" v-model="firstname"> <br>
        lastname: <input type="text" v-model="lastname"> <br>
        {{firstname+'、'+lastname}} <br>
        {{fullname}} <br> 
        age: <input type="text" v-model="age"> <br>
        {{age}}岁,{{show}}
    </template>

    <script>
        import {reactive,toRefs,computed} from 'vue';
        export default {
            name: "ComputedDemo",
            setup(){
                const user = reactive({
                    firstname:'lmonkey',
                    lastname:'com',
                    age:21
                });
                let fullname = computed(()=>{
                    return user.firstname+'--'+user.lastname;
                });
                let show = computed(()=>{
                    if(user.age<20)
                        return '还年轻';
                    else if(user.age<40)
                        return '小青年';
                    else
                        return '岁数不小了'
                });
                return {...toRefs(user),fullname,show}
            }
        }
    </script>
7.watch监听属性

》watch()函数用来监视某些数据项的变化,从而触发某些特定的操作

1.基本语法

watch(()=>{
    console.log(count.value, 'value');
})
const state = reactive({
    count: 0
})
watch(()=>state.count,(count, prevCount)=>{
    console.log(count, prevCount);//变化后的值变化前的值
 })
 watch([()=> state.count, ()=> state.msg].([count, msg], [prevCount,prevMsg])=>{
     console.log(count, msg);
     console.log('------------');
     console.log(prevCount, prevMsg);
 })
》第三个参数immediate:其值是true或false:确认是否以当前的初始值执行handler的函数。
》watchEffect立即执行传入的一个函数,并响应式追踪其依赖,并在其依赖变更时重新运行该函数。

2.使用实例



---- src/views/WatchDemo.vue文件内容
    <template>
        <h2>侦听器watch()api</h2>
        <button @click="a++">a={{a}}</button>
        <button @click="b++">b={{b}}</button>
    </template>

    <script>
        import {ref,watch,watchEffect,reactive,toRefs} from 'vue';
        export default {
            name: "WatchDemo",
            
            // 1.组合式API,reactive变量
            setup(){
                const user = reactive({
                    a:1,
                    b:2
                });
                watch(user,()=>{                           // 只要数据改变,就会触发watch
                    console.log('######')
                });
                watchEffect(()=>{
                    console.log(user.a+'0000000000');
                })
                watch([()=>user.a,()=>user.b],([newA,newB],[oldA,oldB])=>{                     									// 对多个值进行监听
                    console.log(newA+'-----'+oldA);
                    console.log(newB+'+++++'+oldB);
                },{immediate:true});
                return {...toRefs(user)}
            },
            
            // 2.组合式API , ref变量
            setup(){
                let a=ref(1);
                let b=ref(2);

                watch(()=>{
                    console.log(a.value+'---'+b.value)
                });
                watchEffect(()=>{          // 效果类似上面的watch API,但这个API是针对某些数据
                    console.log(a.value+'****'+b.value)
                });
                watch(a,(newA,oldA)=>{                     // 对单个值进行监听
                    console.log(newA+'-----'+oldA);
                },{immediate:true});
                watch([a,b],([newA,newB],[oldA,oldB])=>{                     // 对多个值进行监听
                    console.log(newA+'-----'+oldA);
                    console.log(newB+'+++++'+oldB);
                },{immediate:true});

                return {a,b}
            } 
        }
    </script>
8.Combination生命周期

1.基本知识

生命周期与Composition之间的映射关系
》 beforeCreate -> use setup()
》 created -> use setup()

》 beforeMount -> onBeforeMount
》 mounted -> onMounted
》 beforeUpdate -> onBeforeUpdate
》 updated -> onUpdated
》 beforeUnmount -> onBeforeUnmount
》 unmounted -> onUnmounted

在新版的生命周期函数,可以按需导入到组件中,且只能在setup()函数中使用.

2.使用实例

---- src/views/LifeHook.vue文件内容
    <template>
        <h2>生命周期api</h2>
    </template>

    <script>
        import {onMounted,onUpdated} from 'vue'
        export default {
            name: "LifeHook",
            setup(){

            },
            beforeCreate(){
                console.log('beforeCreate...');
            },
            created(){
                console.log('created...'); // 这两个在setup中是没有的,因为setup会在组件创建之前调用
            },
            beforeMount(){
                console.log('beforeMounted...');
            },
            mounted(){
                console.log('mounted...');
            },
            setup(){
                console.log('setup()...');
                onMounted(()=>{
                    console.log('onMouted....')          // setup中使用的api都要引入
                });
                onUpdated(()=>{
                    console.log('onUpdated....')
                });
            }
        }
    </script>
7.provide,inject多层级通信

1.基本语法

》父子组件:通过props,$emit,【$root,$parent,$children】
》非父子组件: Vuex实现,父子层层传递、$ref

》Vue官网建议,在正常情况下,这两种方式已经能满足绝大多数甚至所有的业务需求,对于应用程序代码应优先使用它们处理。
》provide/inject这对选项允许一个祖先组件向其所有子孙后代组件注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。
》provide就相当于加强版父组件prop,可以跨越中间组件,inject就相当于加强版子组件的props

 
// 1.对象式访问
     根提供变最
        provide(){          
            return {
                title:this.title,
            }
        },
	 后代注入变理
		inject: [ "message" ],

// 2.组合式访问 
    setup(){
        const name = ref("Imonkey')
        const obj = reactive({
            name: "lmonkey",age: "3"
        })
        provide("name" , name);
        provide("network" , obj)
    }
    setup(){
        //用法: inject(key)
        const name = inject('name')
        const animal = inject('animal')
        return {name,animal}
    }

2.使用实例

---- src/views/RootApp.vue文件内容 
    <script>
        import {ref,provide,toRefs ,reactive} from 'vue';
        import TwoComp from "../components/TwoComp";
        export default {
            name: "RootApp",
            components:{
                TwoComp
            },
          // 这种提供数据的方式不是响应式的,子组件无法获取到响应式的数据
           /* provide(){          
                return {
                    title:this.title,
                }
            }*/
            setup(){
                let title=ref('这是根组件提供的数据');
                let user = reactive({
                    name:'lmonkey',
                    age:10
                });
                provide('title',title);
                provide('user',user);               // 也可以传递一个对象
                return {title,...toRefs(user)}
            }
        }
    </script>



---- src/components/ThreeComp.vue文件内容(孙子组件) 
    <script>
       import {inject,toRefs} from 'vue';
       export default {
           name: "ThreeComp",
           // inject:['title']    // 子组件获取的数据不是响应式的
           setup(){
               let title = inject('title');     // 响应式地获取数据
               let user = inject('user');       // 响应式地获取数据
               return {title,...toRefs(user)}    // 同时,子组件改变,父组件的数据也会改变,是双向的
           }
       }
    </script>

二、axios基础

前言:

  1. Axios简单的理解就是ajax的封装

  2. Axios是一个基于promise的 HTTP库,使用Promise管理异步,告别传统callback方式

  3. 支持node端和浏览器端

  4. 丰富的配置项,支持拦截器等高级配置

    项目的两种编程方式-模板式编程和接口式编程
    RestFul API规范(URL,HTP,版本,状态码,返回值,请求条件等规范)
    . GET (SELECT) :从服务器取出资源(一项或多项)。
    · POST (CREATE):在服务器新建一个资源。
    · PUT (UPDATE):在服务器更新资源(客户端提供改变后的完整资源)
    . PATCH (UPDATE):在服务器更新资源(客户端提供改变的属性)
    . DELETE (DELETE) :从服务器删除资源。
    我们配置接口时,这只是一种规范,只是建议大家按照规范来使用而已。

1. html中axios

(1.首先引入模块(cdn服务)
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>

(2.请求数据
	// 默认get方法
    axios('http://localhost/axios/getapi.php').then(res=>{      
        console.log(res);
        console.log(res.data)
    })
    
    // options参数传入
    axios({
        method:"post",                // 默认get方法
        url:'http://localhost/axios/getapi.php',
        headers:{                    // 使用post方法必需添加这个请求头
            'content-type':'application/x-www-form-urlencoded'
        },
        data:{                      // get方法是params参数,post方法是data参数
            usename:"zhangsan",    // 但这种请求数据的方式的参数都是json对象格式
            age:10,
            sex:'nan'
        }
    }).then(res=>{                 // 这里的服务器类型是http
        console.log(res);
        console.log(res.data)
    })
2.安装axios

安装axios模块

   npm install axios -S

1.常用的方法

 
》import axios from 'axios';

》axios.request(config)         
》axios.get(url[, config])
》axios.delete(url[, config])
》axios.head(url[, config])
》axios.post(url[, data[, configll)
》axios.put(url[, data[, config]])
》axios.patch(url[, data[, config]])、

// config参数其实就是一个json对象, 包含url,method,headers,data,params等

**2.使用实例 **


    import axios from "axios";      // 引入axios模块

    // 类型一: Get类型
    // get请求,没有参数
    axios.get('http://localhost/axiosdemo/getapi.php?username=abc').then(res=>{
        console.log(res);
    }); 
    // get请求2,有参数
    axios.get('http://localhost/axiosdemo/getapi.php', {
        params:{id:1}
    }).then(res=>{
        console.log(res);
    }); 
    
    
    
    // 类型二:Post类型 
    // post请求,有参数,(data 是使用query字符串类型的参数)
    axios.post('http://localhost/axiosdemo/getapi.php',
        'name=测试&url=eduwork.cn'
     ).then(res=>{
        console.log(res);
    }); 
    // post请求2,有参数,(data 是使用数组类型的参数)
    const options = { 
        transformRequest:[          // 将数组格式转化成字符串
            function(data) {
                let ret = "";
                for (let it in data) {
                    ret+=  encodeURIComponent(it) +"="+  encodeURIComponent(data[it])+"&";
                }
                return ret;
            }
        ],
        headers: {
            "Montent-Type" : "application/x-www-form-urlencoded"
        }
    }
    axios.post('http://localhost/axiosdemo/getapi.php',
       [name:'测试',url:'eduwork.cn'],
       options
     ).then(res=>{
        console.log(res);
    });
3.axios的并发请求

1.基本语法

》ajax请求过多对页面性能可能会有影响,以及代码不美观,代码过于臃肿,所以我们可以使用axios的并发请求axios.all()
》axios.all()和promise.all()方法是一个道理
》axios.all()这个方法在axios的构造函数是没有的,没在实例对象上。

2.使用实例


    // all方法, 并发地发送多个请求,返回一个数组
    axios.all([
        axios.get('http://localhost/axiosdemo/getapi.php?id=1&name=小明'),
        axios.get('http://localhost/axiosdemo/getapi.php?id=2&name=小红')
    ]).then(res => {
    console.log(res)              // 返回的是一个数组
    }).catch(err => {
        console.log('错误是'+err)
    });

    // .spread方法 将返回的数组再分开处理(不建议)
    axios.all([
        axios.get('http://localhost/axiosdemo/getapi.php?id=1&name=小明'),
        axios.get('http://localhost/axiosdemo/getapi.php?id=2&name=小红')
    ]).then(
        axios.spread((res1,res2)=>{      // axios方法,又可以将结果分开处理
            console.log(res1);
            console.log(res2);
            console.log(res3);
        })
    ).catch(err => {
        console.log(错误是'+err)
    });

4.axios的全局配置

1.基本语法

》做完全局配置之后在发送axios请求时就简单了
    axios.default.baseURL="http://127.0.0.1";
    axios.default.timeout=5000;
    axios.default.headers.post['content-type']='application/x-www-form-urlencoded';
》整理数据
    axios.defaults.transformRequest = function (data){
        data = JSON.stringify(data);
        return data;
    );
 
    axios.defaults.baseURL = 'http://localhost/axiosdemo/';
    axios.defaults.timeout = 5000;

    // get请求
    axios.get('getapi.php?id=1').then(res=>{
    	console.log(res)
    }).catch(err => {
    	console.log('错误是'+err)
    }); 
    // post请求
    axios.post('getapi.php',"id=2&name=小明").then(res=>{
    	console.log(res)
    }).catch(err => {
    	console.log('错误是'+err)
    });
5.axios实例请求

1.基本语法

》有时候后台接口地址有多个并且超时时长不一样,我们不可能在axios中把每个后台请求的域名地址都拼接在URl中,   并且在axios中的config写不同的超时时长,很繁琐,这个时候可以用到axios实例,在实例中可以配置这两种参数。
》假如新建了一个axios实例但是没有参数,取得就是全局的配置值,实例中如果有则优先取实例中的
》axios实例的相关配置(config参数)
   baseURL:请求的域名基本地址(如: http://localhost:8080)
   timeout:后端定义的超时时长(默认是1000ms)
   url:请求的路径(如:/data.json)
   method:精求方法(get、post...headers:设置请求头
   params:请求的参数拼接在url中
   data:请求的参数放在request body中

2.使用实例


    let work = axios.create({
        baseURL:'http://localhost/axiosdemo/',
        timeout:5000
    });
    // post请求
        work.post('getapi.php',"id=2&name=小明").then(res=>{
        console.log(res)
    }).catch(err => {
        console.log('错误是'+err)
    }); 
    // get请求
    work.get('getapi.php?id=2&name=小明').then(res=>{
        console.log(res)
    }).catch(err => {
        console.log('错误是'+err)
    });
    // get请求2, options访问
    work({
        url:'getapi.php?id=3&name=小刚'          
    }).then(res=>{
        console.log(res)
    }).catch(err => {
        console.log('错误是'+err)
    });

6.intercepter拦截器

1.基本语法

请求拦截器、响应拦截器,可以在请求服务器数据时,进行其它的显示
》为每个请求都带上的参数,比如token,时间戳等。
》对返回的状态进行判断,比如token是否过期

2.使用实例

    //1.请求拦截器
    //每次发送诘求之前判断是否存在token
    //如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况
    //即使本地存在token,也有可能oken是过期的,所以在响应拦截器中要对返回状态进行判断
    axios.interceptors.request.use(config =>{
        const token = window.localStorage.getItem("token");
        token && (config.headers.Authorization = token);
        return config
    }, error=>{
        return Promise.error(error);
    });

    //2.响应拦截器
    //如果返回的状态码为200,说明接口请求成功,可以正常拿到数据,否则的话抛出错误
    //服务器状态码不是2开头的的情况
    //这里可以眼你们的后台开发人员协商好统一的错误状杰码
    //然后根据返回的达态码进行一些操作,例如登录过期提示,错误提示等等
    axios.interceptors.response.use(response =>{
        if (response.status === 200){
            return Promise.resolve(response);
        }else {
            return Promise.reject(response);
        }
    },error => {
        if (error.response.status){
            return Promise.reject(error.response);
        }
    });
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值