Bootstrap

Vue学习笔记

一、Vue概述

(一)Vue是什么

    Vue.js(读音 /vjuː/, 类似于 view 是一套构建用户界面的渐进式框架。Vue 只关注视图层, 采用自底向上增量开发的设计。
    Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。
    Vue.JS是优秀的前端 JavaScript 框架

(二)为什么学习Vue

    随着项目业务场景的复杂,传统模式(html+jquery)已无法满足需求,就出现了Angular/React/Vue等框架
企业需求、主流框架之一、易用、灵活、高效

(三)Vue能做什么

最大程度上解放了 DOM 操作
单页web项目开发
传统网站开发

二、Vue核心特征

解耦视图与数据
② M-V-VM模型 关注模型和视图
    M:即Model,模型,包括数据和一些基本操作。
    V:即View,视图,页面渲染结果
    VM:即View-Model,模型和视图间的双向操作
双向数据绑定

(一)MVVM之前

    开发人员从后端获取需要的数据模型,然后要通过DOM操作Model渲染到View中。而后当用户操作视图,我们还需要通过DOM获取View中的数据,然后同步到Model

(二)MVVM之后

    MVVM中的VM要做的事情就是把DOM操作完全封装起来,开发人员不用再关心ModelView之间是如何互相影响的:
- 只要我们Model发生了改变,View上自然就会表现出来。
- 当用户修改了ViewModel中的数据也会跟着改变
把开发人员从繁琐的DOM操作中解放出来,把关注点放在如何操作Model

三、Vue入门

    NPMNode提供的模块管理工具,可以非常方便的下载安装很多前端框架,包括JqueryAngularJSVueJs都有。为了后面学习方便,我们先安装nodeNPM工具
    node.js下载地址:https://nodejs.org/en/download/,安装完成Node应该自带了NPM了,在控制台输入npm -v查看
    注:
       ① v12.16.2以上版本就不在支持window7系统。
       ② npm默认的仓库地址是在国外网站,速度较慢,建议大家设置到淘宝镜像。但是切换镜像是比较麻烦的。推荐一款切换镜像的工具:nrm  
           安装命令:npm install nrm -g 这里-g代表全局安装
           查看npm的仓库列表:nrm ls
           指定镜像源:nrm use taobao
           测试速度:nrm test npm

(一)下载安装

vue是一个前端框架,也是其实是一个js文件,下载vue.js文件并在页面中引入
vue.js的下载方式:
可以引入在线的vue.js(公共的CDN服务)
    <!-- 开发环境版本,包含了用帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
   
    <!-- 生产环境版本,优化了尺寸和速度 -->
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
可以离线下载vue.js
    开发版本: https://vuejs.org/js/vue.js
    生产版本: https://vuejs.org/js/vue.min.js
③ npm包资源管理器,可以下载vue.js(推荐)
    初始化:npm init -y
    安装vuenpm install vue --save
    注:切记重启计算机

(二)第一个vue
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>第一个Vue</title>
    <script src="vue.js"></script> 
</head>
<body>
    <div id="app"><h2>{{name}}<h2></div>  
    <script type="text/JavaScript">       
        //1、创建vue对象
        var app = new Vue({
            el:"#app",
            data:{
                name:"Deam!"
            }
        })
    </script>

</body>
</html>


Vue参数详解:
    1. body,设置Vue管理的视图<div id="app"></div>
    2. 引入vue.js
    3. 实例化Vue对象 new Vue();
    4. 设置Vue实例的选项:eldata...
       new Vue({选项:});
    5. <div id='app'></div>中通过{{ }}使用data中的数据

四、Vue常见指令

         指令 (Directives) 是带有 v- 前缀的特殊attribute。是Vue框架提供的语法,扩展了html标签的功能、大部分的指令的值是js的表达式。用于取代DOM操作

(一)v-textv-html

类似innerTextinnerHTML
    ① v-text:更新标签中的内容
    ② v-html:更新标签中的内容/标签

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>V-Html AND V-Text</title>
</head>
<body>

    <div id="mapp">
        <h2 V-html="value"></h2>
        <h2 V-text="value"></h2>
    </div>
    <script src="vue.js"></script>
    <script>
        var mapp = new Vue({
            el:"#mapp",
            data:{
                value:"<i>Deam!</i>"
            }
        })
    </script>
    
</body>
</html>
(二)v-ifv-show

根据表达式的boolean值进行判断是否渲染该元素
 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>V-If AND V-Show</title>
    <script src="vue.js"></script>
</head>
<body>

    <!-- 
    v-if 和v-show的区别:
        v-if:真正意义的渲染,根据条件进行组件的销毁和重组
        v-show:不管条件是什么,都会进行渲染,只是根据值进行css的切换
     -->

    <div id="mapp">
        <p v-if="b">显示吗?</p>
        <p v-show="b">显示</p>
        <p v-if="c">显示吗?</p>
        <p v-show="c">显示</p>
    </div>
    <script>
        new Vue({
            el:"#mapp",
            data:{
                b:true,
                c:false
            }
        })
    </script>
    
</body>
</html>
(三)v-on

        ① 作用:使用 v-on 指令绑定 DOM 事件,并在事件被触发时执行一些 JavaScript 代码。
        ② 语法:
             v-on:事件名.修饰符 = "methods中的方法名";
             v-on的简写方法: @事件名.修饰符 = "methods中的方法名";
        

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>V-on</title>
    <script src="vue.js"></script>
</head>
<body>

    <div  id="mapp">
        <h2>{{num}}</h2>
        <h2>
          <button v-on:click="num++">加加</button>
          <br>
          <button @click="clickFunction()">点我</button>  
          <br>
          <button @click="clickFunctions(num)">继续点我</button>  
          <br>
          <button @click="clickFunction">再加加</button>  
          <br>
          <input type="text" @change="changeFunction()">
        </h2>
        

    </div>
    <script>
        new Vue({
            el:"#mapp",
            data:{
                num:0
            },
            methods:{
                clickFunction:function(){
                    console.log("点我干什么?")
                },
                clickFunctions:function(num){
                    console.log("点我干什么?")
                    console.log(num)
                },
                changeFunction:function(){
                    console.log("内容改变!")
                }
            }
        })
    </script>
    
</body>
</html>
(四)v-for

作用:列表渲染,当遇到相似的标签结构时,就用v-for去渲染
格式:
     1(item,index) in 数组或集合
        参数item:数组中的每个元素
        参数index:数组中元素的下标
     2(value, key, index) in 对象
        参数index:对象中每对key-value的索引 0开始
        参数key:
        参数value:
 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>V-for</title>
    <script src="vue.js"></script>
</head>
<body>
    <div id="mapp">
        <!-- 遍历数组 -->
        <table border="1" cellspacing="0" align="center">
            <tr v-for="(item,index) in students">
                <td>{{index}}</td>
                <td>{{item.id}}</td>
                <td>{{item.name}}</td>
                <td>{{item.age}}</td>
                <td>{{item.功夫}}</td>
            </tr>
        </table>
        <!-- 遍历对象 -->
        <form align="center">
            <p v-for="(value, key, index) in user">
                <label>{{key}}</label>:<input type="text" v-model="value">
            </p>
        </form>
    </div>

    <script>
        new Vue({
            el:"#mapp",
            data:{
                students:[
                    {id:"1001",name:"令狐冲",age:32,功夫:"吸星大法、独孤九剑"},
                    {id:"1002",name:"欧阳锋",age:58, 功夫:"蛤蟆功、灵蛇拳"},
                    {id:"1003",name:"杨过",age:28, 功夫:"黯然销魂掌、玄铁剑法"},
                    {id:"1004",name:"郭靖",age:35, 功夫:"降龙十八掌、九阴真经"},
                    {id:"1005",name:"张无忌",age:25, 功夫:"九阳神功、乾坤大挪移"},
                    {id:"1006",name:"段誉",age:22, 功夫:"六脉神剑、凌波微步"},
                    {id:"1007",name:"虚竹",age:27, 功夫:"天山六阳掌、生死符"},
                    {id:"1008",name:"乔峰",age:33, 功夫:"降龙十八掌、擒龙功"},
                    {id:"1009",name:"小龙女",age:24, 功夫:"玉女心经、左右互搏术"},
                    {id:"1010",name:"周伯通",age:60, 功夫:"空明拳、双手互搏"},
                    {id:"1011",name:"黄药师",age:55, 功夫:"弹指神通、落英神剑掌"},
                    {id:"1012",name:"欧阳锋",age:58, 功夫:"蛤蟆功、灵蛇拳"}
                ],
                user:{
                    id:"0000",
                    name:"岳不群",
                    age:"60"
                }
            }
        })
    </script>
</body>
</html>

(五)v-bind

作用: 可以绑定标签上的任何属性
格式:v-bind:属性=""
简写格式::属性=""
属性值一部分进行替换的格式::属性="'常量值' + vue对象data中的数据"
 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>V-bind</title>
    <script src="vue.js"></script>
</head>
<body>
    <div id="mapp">
        <font v-bind:color="b">Its Beaning a long day.</font>
        <font :color="r">Without you my friend.</font>
        <a :href="'https://'+baidu">Deam!</a>
    </div>

    <script>
        new Vue({
            el:"#mapp",
            data:{
                b:"blue",
                r:"red",
                baidu:"www.baidu.com"
            }
        })
    </script>
    
</body>
</html>
(六)v-model

作用:表单元素的绑定
特点:双向数据绑定
    1vue对象中的数据发生变化可以更新到界面
    2)通过界面可以更改vue对象中数据
    3v-model 会忽略所有表单元素的 value checked selected 特性的初始值而总是将 Vue 例的数据作为数据来源。应该在data选项中声明初始值。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>V-model数据的双向绑定</title>
    <script src="vue.js"></script>
</head> 
<body>
    <div id="mapp">
        <form>
            用户名:<input type="text" :value="name">{{name}}
            用户名:<input type="text" V-model:value="name">{{name}}
            <input type="button" @click="update" value="修改">
        </form>
    <script>
        new Vue({
            el:"#mapp",
            data:{
                name:"徐超一"
            },
            methods:{
                update:function(){
                    this.name="孙莲奔"
                }
            }
        })
    </script>
</body>
</html>

(七)计算属性

在插值表达式中使用js表达式是非常方便的,而且也经常被用到。
但是如果表达式的内容很长,就会显得不够优雅,而且后期维护起来也不方便
 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>计算属性</title>
    <script src="vue.js"></script>
</head>
<body>
    <div id="mapp">
        <h2>
            原始BirthDay:<span>{{birthday}}</span>
            <br>
            没有使用计算属性的BirthDay:<span>{{new Date(birthday).getFullYear()+'-'+new Date(birthday).getMonth()+1+'-'+new Date(birthday).getDate()}}</span>
            <br>
            使用计算属性的BirthDay:<span>{{getBirthday}}</span>
        </h2>
    </div>
    <script>
        new Vue({
            el:"#mapp",
            data:{
                birthday:1610669793429
            },
            computed:{
                getBirthday(){
                    return new Date(this.birthday).getFullYear()+'-'+new Date(this.birthday).getMonth()+1+'-'+new Date(this.birthday).getDate()
                }
                
            }
        })
    </script>
    
</body>
</html>
(八)watch

watch可以让我们监控一个值的变化。从而做出相应的反应。
 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>watch</title>
    <script src="vue.js"></script>
    <!-- watch可以让我们监控一个值的变化。从而做出相应的反应。 -->
</head>
<body>
    <div id="mapp">
        <input type="text" v-model="hello">
    </div>
    <script>
        new Vue({
            el:"#mapp",
            data:{
                hello:"hello"
            },
            watch:{
                hello(newValue,oldValue){
                    console.log(newValue,oldValue)
                }
            }

        })
    </script>
    
</body>
</html>

五、Vue的生命周期

    每个 Vue 实例在被创建时都要经过一系列的初始化过程 :创建实例,装载模板,渲染模板等等。Vue为生命周期中的每个状态都设置了钩子函数(监听函数)。每当Vue实例处于不同的生命周期时,对应的函数就会被触发调用。
Vue的生命周期


    (一)理解


        每个 Vue 实例在被创建时都要经过一系列的初始化过程 :创建实例,装载模板,渲染模板等等。 Vue
        为生命周期中的每个状态都设置了钩子函数(监听函数)。每当 Vue 实例处于不同的生命周期时,对应的函数 就会被触发调用。


    (二)钩子函数


        1 、创建时的四个事件
            beforeCreate :实例被创建之前执行
            created : created 执行时, data 和 methods 都已经被初始化好了!
            beforeMount : beforeMount 执行时,模板已经在内存中编辑完成了,尚未被渲染到页面中
            mounted :内存中的模板已经渲染到页面,用户已经可以看见内容
        2 、运行中的两个事件
            beforeUpdate : beforeUpdate 执行时,内存中的数据已更新,但是页面尚未渲染
            updated : updated 执行时,内存中的数据已更新,并且页面已经被渲染 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue的生命周期</title>

    <script src="vue.js"></script>
</head>
<body>
    <div id="mapp"> 
        <p>{{message}}</p>
    </div>
    <script>
        new Vue({
            el:"#mapp",
            data:{
                message:""
            },

            beforeCreated(){
                this.message="创建之前"
            },
            created(){
                this.message="创建之后"
            }
        })
    </script>
    
</body>
</html>

六、组件

(一)介绍

         组件( Component )是 Vue.js 最强大的功能之一。

(二)作用

    1 、组件可以扩展 HTML 元素,封装可重用的代码。
    2 、组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树 。

(三)组件的定义

全局组件的特点:
    1 、组件其实也是一个 Vue 实例,因此它在定义时也会接收: data 、 methods 、生命周期函数等。
    2 、不同的是组件不会与页面的元素绑定,否则就无法复用了,因此没有 el 属性。
    3 、组件渲染需要 html 模板,所以增加了 template 属性,值就是 HTML 模板。
    4 、全局组件定义完毕,任何 vue 实例都可以直接在 HTML 中通过组件名称来使用组件了。
    5 、 data 的定义方式比较特殊,必须是一个函数。
    注:定义组件要在 Vue 对象之前声明 -->

(四)定义全局组件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>全局组件</title>
    <script src="vue.js"></script>
</head>
<body>
    <div id="mapp">
        <btn></btn>
    </div>
    <script>

        //定义全局组件  参数1:组件名   参数2:组件参数
        Vue.component("btn",{
            template:"<button @click='count++'>加加</botton>{{count}}",
                data(){
                    return{
                        count:0
                    }
                }
        })
        new Vue ({
            el:"#mapp"
        })
    </script>
</body>
</html>


特点:
- 组件其实也是一个Vue实例,因此它在定义时也会接收:datamethods、生命周期函数等
- 不同的是组件不会与页面的元素绑定,否则就无法复用了,因此没有el属性。
- 但是组件渲染需要html模板,所以增加了template属性,值就是HTML模板
- 全局组件定义完毕,任何vue实例都可以直接在HTML中通过组件名称来使用组件了。
- data的定义方式比较特殊,必须是一个函数。

注:定义组件要在Vue对象之前声明

(五)定义局部组件

    一旦全局注册,就意味着即便以后你不再使用这个组件,它依然会随着Vue的加载而加载。因此,对于一些并不频繁使用的组件,我们会采用局部注册。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>局部组件</title>
    <!-- 
局部组件的特点:
    1 、一旦全局注册,就意味着即便以后你不再使用这个组件,它依然会随着 Vue 的加载而加载。
    2 、对于一些并不频繁使用的组件,我们会采用局部注册。
    4 、 components 就是当前 vue 对象子组件集合。其 key 就是子组件名称,其值就是组件对象的属性
    5 、效果与刚才的全局注册是类似的,不同的是,这个 conn 组件只能在当前的 Vue 实例中使用
    注:定义组件要在 Vue 对象之前声明 -->
    <script src="vue.js"></script>
    <style>
        button {
            font-size: 20px;
            width: 150px;
            height: 50px;
            display: block;
            margin: 20px auto;
        }
    </style>
</head>
<body>
    <div id="mapp">
            <conn></conn>      
    </div>
    <script>

        //声明局部变量
        const conn={
            template:"<button @click='count++'>{{count}}</button>",
            data(){
                return{
                    count:1
                }
            }
        }
        new Vue({
            el:"#mapp",
            components:{
                conn:conn   //注册局部变量
            }
            
        })
    </script>
    
</body>
</html>


- components就是当前vue对象子组件集合。
  - key就是子组件名称
  - 其值就是组件对象的属性
- 效果与刚才的全局注册是类似的,不同的是,这个conn组件只能在当前的Vue实例中使用

注:定义组件要在Vue对象之前声明

(六)组件通信

通常一个单页应用会以一棵嵌套的组件树的形式来组织,如下:
- 页面首先分成了顶部导航、左侧内容区、右侧边栏三部分
- 左侧内容区又分为上下两个组件
- 右侧边栏中又包含了3个子组件 

各个组件之间以嵌套的关系组合在一起,那么这个时候不可避免的会有组件间通信的需求。

 

父向子传递
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件通信之父传子</title>
    <script src="vue.js"></script>
</head>
<body>
    <div id="mapp">
        <par content="Hello h2"></par>
    </div>
    <script>
        Vue.component("par",{
            template:"<h2>{{content}}</h2>",
            props:["content"]               //可以作为一个标签的属性进行赋值操作
        })

        new Vue({
            el:"#mapp"
        })
    </script>
    
</body>
</html>

传递复杂数据
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>传递复杂数据</title>
    <script src="vue.js"></script>
</head>
<body>
    <div id="mapp">
        <my-list :items="lessons"></my-list>
    </div>
    <script>
        const myList={
            template:"<ul><li v-for='item in items':key='item,id'>{{item.id}}:{{item.name}} </li></ul>",
            props:{
                items:{
                    type:Array,
                    default:[]
                }
            }
        }
        new Vue({
            el:"#mapp",
            components:{
                myList:myList
            },
            data:{
                lessons:[
                    {id:"1001",name:"莎莎"},
                    {id:"1002",name:"乖乖"},
                    {id:"1003",name:"东新"}
                ]
            }
        })
    </script>
    
</body>
</html>


注:单页面中父组件和子组件的使用 自定义标签时的问题。如 <my-list></my-list> <my-list />


子向父传递
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>子组件从父组件传递信息</title>
    <script src="vue.js"></script>
</head>

<body>
    <div id="mapp">
        <h2>{{num}}</h2>
        <!-- 引入了名为 btn 的自定义组件,并通过 v-bind(缩写为 :)将父组件中的 num 属性传递给子组件。 -->
        <btn :num="num"></btn>  
        

        <!--  报错:Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "num" -->
    </div>
    <script>
        Vue.component("btn",{
            template:"<div><button @click='num++'>{{num}}</button><br><button @click='num--'>{{num}}</button></div>",
            props:['num']       //设置一个属性
        }
        )
        new Vue({
            el:"#mapp",
            data:{
                num:0
            }
        })
    </script>
    
</body>
</html>


报错:[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "num"
原因:子组件接收到父组件属性后,默认是不允许修改的
解决:既然只有父组件能修改,那么加1和减1的操作一定是放在父组件
var app = new Vue({
    el:"#app",
    data:{
        num:0
    },
    methods:{ // 父组件中定义操作num的方法
        (){
            this.num++;
        },
        decrement(){
            this.num--;
        }
    }
})
点击按钮是在子组件中,那就是说需要子组件来调用父组件的函数,可以通过v-on指令将父组件的函数绑定到子组件上
<div id="app">
        <h2>num: {{num}}</h2>
        <btn :num="num" @incre="increment" @decre="decrement"></btn>
</div>
当子组件中按钮被点击时,调用绑定的函数
Vue.component("btn",{
            template:"<div><button @click='plus'>1</button> <button @click='reduce'>1</button></div>",
            props:['num'],
            methods:{
                plus(){
                    this.$emit("incre");
                },
                reduce(){
                    this.$emit("decre");
                }
            }
        })
  注:vue提供了一个内置的this.$emit函数,用来调用父组件绑定的函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>解决报错</title>
    <script src="vue.js"></script>
</head>
<body>
    <div id="mapp">
        <h2>{{num}}</h2>
        <!-- 引入了名为 btn 的自定义组件,并通过 v-bind(缩写为 :)将父组件中的 num 属性传递给子组件。 -->
        <btn :num="num" @incre="increment" @decre="decrement"></btn>  
        
    </div>
    <script>
        Vue.component("btn",{
            template:"<div><button @click='plus'>加加</button><button @click='reduce'>减减</button></div>",
            props:['num'],       //设置一个属性num
            methods:{
                plus(){
                    this.$emit("incre");            //使用Vue的内置函数,获取父组件的信息
                },
                reduce(){
                    this.$emit("decre");
                }
            }
        }
        )
        new Vue({
            el:"#mapp",
            data:{
                num:0
            },
            methods:{
                increment(){
                    this.num++
                },
                decrement(){
                    this.num--
                }
            }
        })
    </script>
    
    
</body>
</html>

七、Vue的Ajax(axios)

Vue.js中发送网络请求本质还是ajax,我们可以使用插件方便操作。
1. vue-resource: Vue.js的插件,已经不维护,不推荐使用
2. axios :不是vue的插件,可以在任何地方使用,推荐
3. 通过Http请求的不同类型(POST/DELETE/PUT/GET)来判断是什么业务操作(CRUD ) HTTP方法规则举例
说明:
    ① POST Create 新增一个没有id的资源
    ② GET  Read   取得一个资源
    ③ PUT  Update 更新一个资源。或新增一个含 id 资源(如果 id 不存在)
    ④ DELETE  Delete 删除一个资源

(一)安装

方式1:使用npm安装
命令:npm install axios

我们直接导入对应的本地依赖就行

方式2:使用cdn链接axios
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

(二)axios请求
axios({
    // 请求方式
 method: 'post',
 url: 'api',
 // 传递参数
 data: obj,
 // 设置请求头信息
 headers: {
   key: value
 },
 responseType: 'json'
}).then(response => {
 // 请求成功
 let res = response.data;
 console.log(res);
}).catch(error => {
 // 请求失败,
 console.log(error);
});

(三)GET请求
axios.get('/user?id=12345')
 .then(response => {
     console.log(response.data);
 })
 .catch(error => {
     console.dir(error)
});
(四)POST请求
axios.post('/user', "name=迪丽热巴&age=23") .then(response => {
     console.log(response.data);
 })
 .catch(error => {
     console.dir(err)
});

补充:
    为方便起见,为所有支持的请求方法提供了别名
   

 axios.request(confifig)
    axios.get(url[, confifig])
    axios.delete(url[, confifig])
    axios.head(url[, confifig])
    axios.post(url[, data[, confifig]])
    axios.put(url[, data[, confifig]])
    axios.patch(url[, data[, confifig]])

(五)跨域问题

什么是跨域?
    指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制。
什么是同源策略?
    是指协议,域名,端口都要相同,其中有一个不同都会产生跨域,在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
跨域问题怎么出现的?
    开发一些前后端分离的项目,比如使用 Servlet + Vue 开发时,后台代码在一台服务器上启动,前台代码在另外一台电脑上启动,此时就会出现问题。
  比如:

    后台 地址为 http://192.168.70.77:8081
    前台 地址为 http://192.168.70.88:8080
  此时 ip 端口号不一致, 不符合同源策略,造成跨域问题。

如何解决:
    方式1:后台解决(自定义过滤器)
        

package com.jn.fliter;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebFilter("/*")
public class MyFliter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) resp;
        HttpServletRequest request = (HttpServletRequest) req;

        // 不使用*,自动适配跨域域名,避免携带Cookie时失效
        String origin = request.getHeader("Origin");
        response.setHeader("Access-Control-Allow-Origin", origin);

        // 自适应所有自定义头
        String headers = request.getHeader("Access-Control-Request-Headers");
        response.setHeader("Access-Control-Allow-Headers", headers);
        response.setHeader("Access-Control-Expose-Headers", headers);

        // 允许跨域的请求方法类型
        response.setHeader("Access-Control-Allow-Methods", "*");
        // 预检命令(OPTIONS)缓存时间,单位:秒
        response.setHeader("Access-Control-Max-Age", "3600");
        // 明确许可客户端发送Cookie,不允许删除字段即可
        response.setHeader("Access-Control-Allow-Credentials", "true");

        filterChain.doFilter(req, resp);
    }
}
(六)案例

在idea里面新建一个web项目,过滤器使用上诉代码 

后台Servlet

package com.jn.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/axiosTest")
public class AxiosServlet extends HttpServlet {
    @Override
    //用于测试axios的前端访问以及get请求访问
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1、获取请求参数
        String name = req.getParameter("name");
        String age = req.getParameter("age");
        System.out.println(name + "\t" + age);

        //2、响应数据
        String json = "{\"name\":\"张无忌\",\"age\":\"18\"}";
        PrintWriter writer = resp.getWriter();
        writer.print(json);
    }

    @Override
    //用于axios的post请求访问
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1、获取请求参数
        String name = req.getParameter("name");
        String age = req.getParameter("age");

        //2、响应数据
        String json = "{\"name\":\"赵敏\",\"age\":\"17\"}";
        PrintWriter writer = resp.getWriter();
        writer.print(json);
    }
}

前台代码:


axios的请求方式
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue的axios请求</title>
 <script src="vue.js"></script>
 <script src="axios.min.js"></script>
</head>
<body>
    <div id="mapp">
        <button @click="getdata">点击获取数据</button>
    </div>
    <script>
        new Vue({
            el:"#mapp",
            methods:{
                getdata(){
                    //方式一:发送axiox请求
                    axios({
                        method:"GET",       //请求方式
                        url:"http://localhost:8080/AxiosProject_war_exploded/axiosTest",
                        data:"",            //携带参数
                        responseType:"json"
                    }).then(response=>{     //发送成功
                        let rel = response.data
                        console.log(rel)
                    }).catch(error =>{      //发送失败
                        console.log(error)
                    })
                }
            }
        })
    </script>
    
</body>
</html>

然后启动tomcat进行测试

 

 

注:别忘了配置跨域过滤器哦

get请求方式
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue的axios请求</title>
 <script src="vue.js"></script>
 <script src="axios.min.js"></script>
</head>
<body>
    <div id="mapp">
        <button @click="getdata">点击获取数据</button>
    </div>
    <script>
        new Vue({
            el:"#mapp",
            methods:{
                getdata(){
                    //方式二:发送axioxGet请求
                    axios.get("http://localhost:8080/AxiosProject_war_exploded/axiosTest",{
                    }).then(response=>{     //发送成功
                        let rel = response.data
                        console.log(rel)
                    }).catch(error =>{      //发送失败
                        console.log(error)
                    })
                }
            }
        })
    </script>
    
</body>
</html>

 

post请求方式
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue的axios请求</title>
 <script src="vue.js"></script>
 <script src="axios.min.js"></script>
</head>
<body>
    <div id="mapp">
        <button @click="getdata">点击获取数据</button>
    </div>
    <script>
        new Vue({
            el:"#mapp",
            methods:{
                getdata(){
                    //方式二:发送axioxGet请求
                    axios.post("http://localhost:8080/AxiosProject_war_exploded/axiosTest","name=xx&&age=xx").then(response=>{     //发送成功
                        let rel = response.data
                        console.log(rel)
                    }).catch(error =>{      //发送失败
                        console.log(error)
                    })
                }
            }
        })
    </script>
    
</body>
</html>

 

;