第二阶段(day19)vue基本用法

1.什么是vue

是一套前端框架,简化前端大量的jquery,原生js的重复DOM操作代码。用来简化开发。

是一套数据驱动视图的前端框架,基于MVVM架构,M:model数据,V:view视图,vm:viewModel视图数据监听器,当数据改变,修改视图;当视图发生变化,修改model数据。是一种数据双向绑定监听的实现。

是国人尤雨溪开发。

示例:

在HBuilder中新建vue项目,起名day19_vue

先用之前的方式写一个例子:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <h1 id="mytitle">mytitle</h1>
        <input type="button" value="测试" οnclick="changeTitle()" />
    </body>
    <script>
        function changeTitle(){
            document.getElementById("mytitle").innerHTML = "测试标题";
        }
    </script>
</html>

这是命令式的js代码,先从dom结构找到元素,再找元素属性,再确定要赋的值,最后把内容显示到页面中。最后一步叫页面渲染render,不是我们控制的。

如果编写页面效果,比如改变标题等等,要改变的内容比较多时,以上过程会一遍一遍的走。

再看以下代码:

    <script>
        var myobj={};
        myobj.a="abc";
        console.log(myobj.a);     //abc
        
        //赋值操作是包含在Object里的一个方法
        Object.defineProperty(myobj,"b",{   //js给对象定义属性,第三个参数是描述信息desc,用json设置扩展对象时的相关参数,最关键的一个就是value  
           value:"jack"
        })
        console.log(myobj.b);    //jack
    
    </script>

在这里也可进行数据的读写,get和set方法。

<script>
        var myobj={};
        
        Object.defineProperty(myobj,"b",{  
           get:function(){
               console.log("尝试获取b的值");    
           },
           set:function(){                         //给b赋值时该函数会触发
               console.log("尝试设置b的值");  
           }
        })
        console.log(myobj.b);    //undefined
        myobj.b = 10;   
    
    </script>

用一个公共变量去写:

<script>
        var myobj={};
        var temp;
        
        Object.defineProperty(myobj,"b",{  
           get:function(){
               console.log("尝试获取b的值");  
               return temp;
           },
           set:function(newVal){                         
               console.log("尝试设置b的值 改成"+newVal);  
               temp = newVal;
           }
        })
        
        myobj.b = 10;   
        console.log(myobj.b); 
        
    </script>

结果,控制台输出:

尝试设置b的值 改成10

尝试获取b的值

10

用它来写上面的按钮的例子:

    <body>
        <h1 id="mytitle">mytitle</h1>
        <input type="button" value="测试" οnclick="changeTitle()" />
    </body>
    <script>
        var myobj={};
        var temp;
        
        Object.defineProperty(myobj,"b",{      //相当于一套工具,重写get,set方法
           get:function(){
               console.log("尝试获取b的值");  
               return temp;
           },
           set:function(newVal){                         
               console.log("尝试设置b的值 改成"+newVal);  
               temp = newVal;  //设置值
               document.getElementById("mytitle").innerHTML = temp;   //渲染页面
           }
        })
        
        function changeTitle(){
            myobj.b = "jack";
        }
        
    </script>

这就是MVVM模式,把核心要干的事想明白。这里核心的事是js里改数据,页面里元素展现的效果要变。将他们写成公共代码,只需改变数据,自动在页面中变成相应的效果。

以上就是vue底层的一部分工作。

前端框架还会使用虚拟dom,用于提升页面渲染效果。

    <script>
        function changeTitle(){
            document.getElementById("mytitle").innerHTML = "测试标题1";
            document.getElementById("mytitle").innerHTML = "测试标题2";
            document.getElementById("mytitle").innerHTML = "测试标题3";
            document.getElementById("mytitle").innerHTML = "测试标题4";
        }
        
    </script>

触发按钮后,最终页面显示的是测试标题4,实际上做了四次页面渲染。

可以用变量去改进:

    <script>
        function changeTitle(){
            var temp
            temp = "测试标题1";
            temp = "测试标题2";
            temp = "测试标题3";
            temp = "测试标题4";
            document.getElementById("mytitle").innerHTML = temp;
        }
        
    </script>

这样,只会渲染一次。

实际上是有一套标准:

   <script>
        function changeTitle(){
            var temp
            temp = "测试标题1";
            temp = "测试标题2";
            temp = "测试标题3";
            temp = "测试标题4";
            //document.getElementById("mytitle").innerHTML = temp;
            console.log(document);    //document对象就是dom树对象
        }
        
    </script>

最终调取渲染页面的代码时不让自己调取,由底层自己找到dom树,由我们告知操作哪个元素,剩下的事底层做。

以上就是虚拟dom 的底层原理,由虚拟dom过渡底层的修改,最终只做一次渲染。

总结:使用MVVM模式,只关注数据;不直接操作dom树,页面渲染效率提升。

前端框架有三个:vue,react,angular。他们的语法完全不同,但思想都是接近的,都是MVVM模式和虚拟dom。

2.vue的使用

2.1vue写法

在项目下新建vue介绍.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="js/v2.6.10/vue.js" type="text/javascript" charset="UTF-8"></script>   <!-- 引入vue -->
    </head>
    <body>
        <div id="mydiv">
            测试数据{{myval}}   
        </div>
    </body>
    <script>
        new Vue({     //创建vue对象,参数是json格式
        //要告知指定要监控的页面数据的分标签,然后帮助做自动化的响应式数据的流程。 响应式数据就是数据一遍,页面元素自动一遍。
            el:"#mydiv",
            data:{
                myval:"abc" 
            }
        })   
    
    </script>
</html>

运行,结果页面输出:测试数据abc

两个大括号(叫差值表达式)就是vue将变量值输出到页面的指令。

vue对象在使用时经常会读取:

    <script>
        var myvue = new Vue({     
            el:"#mydiv",
            data:{
                myval:"abc" 
            }
        })   
    
        console.log(myvue); 
    </script>

在控制台:

在vue对象的data部分,设置了myval值,自动生成了get,set方法。也能看到配置的el对应的属性。data里的数据myval其实直接放在了第一层,在data前两行也可看到myval。

vue里配置属性都是以$符号加对应属性名进行的。该符号在jquery里表示jquery对象,故使用vue时不能使用jquery。

可读取配置的属性:

读根标签:

console.log(myvue.$el); 

控制台输出:

<div id="mydiv">测试数据abc</div>

读数据:

console.log(myvue.$data); 

改数据:

console.log(myvue.$data.myval="jack");

操作模板里的键值对时,$data可省略:(仅仅是对data数据的优化,因为data的value放在了第一层)

console.log(myvue.myval="jack");

从现在开始会写一些HTML(ES6)之后的新语法。

①.之前定义变量会用var,ES6之后多了两个。

先看let:

    <script>
        var temp1 = 10;
        let temp2 = 10;
        console.log(temp1);  //10
        console.log(temp2);  //10
        
        for(var i=0;i<10;i++){
            console.log(i);
        }
        console.log(i);      //10  循环外读i,会读到10。10是循环最后走完不满足判断条件之后出来的。从循环外读循环内使用的变量,从语法上并不合理。
         
        for(let j=0;i<10;i++){   //let多了函数块内的作用域
            console.log(j);
        } 
        console.log(j);      //此时报错,在循环外读j,会告知没有定义。let语法上会更严格,有块级作用域。
        
    </script>

js里变量的作用域有:全局,函数内。let多加了一个块级作用域,指代码块,如上循环的代码就是一个典型的代码块。它使变量只在块内生效。

const:

<script>
  const temp3 = 10;  //用来定义常量
  temp3 = 11;        //报错,告知是常量,不可写操作   
</script> 

②.ES6之后提供的拼接的语法

console.log("我的字符串"+temp3+"!!!!");   //我的字符串10!!!!     之前用+拼接
console.log(`我的字符串${temp3}!!!!`);    //我的字符串10!!!!

这和vue没关系,是js里的功能。

③.定义匿名函数,ES6之后也可简化:

      Object.defineProperty(myobj,"b",{      
           get:function(){
               console.log("尝试获取b的值");  
               return temp;
           },
           set:function(newVal){                         
               console.log("尝试设置b的值 改成"+newVal);  
               temp = newVal;  
               document.getElementById("mytitle").innerHTML = temp;  
           }
        }) 
        
        //简化: 
        Object.defineProperty(myobj,"b",{      
           get(){
               console.log("尝试获取b的值");  
               return temp;
           },
           set(newVal){                         
               console.log("尝试设置b的值 改成"+newVal);  
               temp = newVal;  
               document.getElementById("mytitle").innerHTML = temp;  
           }
        }) 

2.2vue常用指令

1.差值表达式{{}}

作用就是把变量显示在页面中。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="js/v2.6.10/vue.js" type="text/javascript" charset="UTF-8"></script>
    </head>
    <body>
        <div id="mydiv">
            {{myval}}
        </div>
    </body>
     <script>
        var option = {
            el:"#mydiv",
            data:{
                myval:"测试"
            }
        };
        
        new Vue(option);
        
    </script>
</html>

结果:页面输出测试

2.v-html

可解析html标签。和差值表达式的主要区别是里面可以加标签。

    <body>
        <div id="mydiv">
            {{myval}}
            <div v-html="myhtml">
                
            </div>
        </div>
    </body>
    <script>
        var option = {
            el:"#mydiv",
            data:{
                myval:"测试",
                myhtml:"<h1>测试</h1>"
            }
        };
        
        new Vue(option);
        
    </script>

使用的不多,可用以下代码代替:

<h1>{{myval}}</h1>

3.v-bind

给元素的属性绑定变量

之前:

<input type="text" value="abc" />

如果想让变量和输入框里的值有关联:

    <body>
        <div id="mydiv">
          <input type="text" v-bind:value="mytest" />
        </div>
    </body>  
    <script>
        var option = {
            el:"#mydiv",
            data:{
                mytest:"abc123"
            }
        };
        
        let myvue = new Vue(option);
        myvue.mytest = "jack";
        
    </script> 

结果:页面文本框默认值变为jack

class属性也可绑定,但较特殊:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="js/v2.6.10/vue.js" type="text/javascript" charset="UTF-8"></script>
        <style>
            .cls1{
                background-color:lightcoral;
            }
            .cls2{
                border:1px solid black;
            }
            .cls3{
                width:100px;
                height:100px;
            }
        </style>
    </head>
    <body>
        <div id="mydiv">
          <div v-bind:class="mycls">mydiv</div>
        </div>
    </body>  
    <script>
        var option = {
            el:"#mydiv",
            data:{
                mycls:"cls1"
            }
        };
        
        let myvue = new Vue(option);
        myvue.mycls = "jack";
        
    </script>
</html>

但是class属性允许多值:

    <script>
        var option = {
            el:"#mydiv",
            data:{
                mycls:"cls1 cls2"
            }
        };
        
        let myvue = new Vue(option);
        
    </script>

此时就是两个样式。

但样式切换比较麻烦:

    <body>
        <div id="mydiv">
          <div v-bind:class="{'cls1':mycls1,'cls2':mycls2,'cls3':mycls3}">mydiv</div>
        </div>
    </body>  
    <script>
        var option = {
            el:"#mydiv",
            data:{
                mycls1:true,
                mycls2:true,
                mycls3:true
            }
        };
        
        let myvue = new Vue(option);
        
    </script>

此时三个样式全部生效,不想让哪个生效,改成false即可。

想用一个搞定也行:

    <body>
        <div id="mydiv">
          <div v-bind:class="{'cls1':mycls1,'cls2':mycls1,'cls3':mycls1}">mydiv</div>
        </div>
    </body>  
    <script>
        var option = {
            el:"#mydiv",
            data:{
                mycls1:true
            }
        };
        
        let myvue = new Vue(option);
        
    </script>

还可以使用多个class属性,需要控制的样式用v-bind控制,不需要控制的不用加v-bind

<head>
        <meta charset="utf-8">
        <title></title>
        <script src="js/v2.6.10/vue.js" type="text/javascript" charset="UTF-8"></script>
        <style>
            .cls1{
                background-color:lightcoral;
            }
            .cls2{
                border:1px solid black;
            }
            .cls3{
                width:100px;
                height:100px;
            }
            .cls4{
                background-color:lightgreen;
            }
        </style>
    </head>
    <body>
        <div id="mydiv">
          <div class="cls4" v-bind:class="{'cls1':mycls1,'cls2':mycls2,'cls3':mycls3}">mydiv</div>
        </div>
    </body>  
    <script>
        var option = {
            el:"#mydiv",
            data:{
                mycls1:false,
                mycls2:true,
                mycls3:true
            }
        };
        
        let myvue = new Vue(option);
        
    </script>

属性绑定时也可简化,不写v-bind,只保留冒号。

4.v-if

控制页面元素是否可见

    <body>
        <div id="mydiv">
          <div v-if="divshow">
              mydiv2
          </div>
        </div>
    </body>  
    <script>
        var option = {
            el:"#mydiv",
            data:{
                divshow:false
            }
        };
        
        let myvue = new Vue(option);
        
    </script>

此时页面不显示mydiv2

底层是用注释标签<!---->替换掉元素标签。

v-show也是控制元素是否显示:

主要区别是底层不改结构,而是给标签加样式

<div style="display:none;">mydiv2</div>

总结:v-if控制页面元素是否存在(<!-- -->);v-show控制页面元素是否隐藏(display)

除了v-if还有v-else-if和v-else:

    <body>
        <div id="mydiv">
          <div v-if="divshow==1">   <!--通过v-if后面的逻辑条件返回布尔值 -->
              测试1
          </div>
          <div v-else-if="divshow==2">
              测试2
          </div>
          <div v-else>
              测试3
          </div>
        </div>
    </body>  
    <script>
        var option = {
            el:"#mydiv",
            data:{
                divshow:2
            }
        };
        
        let myvue = new Vue(option);
         
    </script>

三个里走一个,如果v-if匹配成功,则页面显示测试1;如果v-else-if匹配成功,则页面显示测试2;如果前两个都不匹配,则走v-else,页面输出测试3。

5.v-on

绑定事件

    <body>
        <div id="mydiv">
           <input type="button" value="测试按钮" v-on:click="myFun()" />
        </div>
    </body>  
    <script>
        var option = {
            el:"#mydiv",
            methods:{
                myFun:function(){
                    console.log("按钮被点击了");
                }
            }
        };
        
        let myvue = new Vue(option);
         
    </script> 

也有简写:

    <body>
        <div id="mydiv">
           <input type="button" value="测试按钮" @click="myFun()" />
        </div>
    </body>  
    <script>
        var option = {
            el:"#mydiv",
            methods:{
                myFun(){
                    console.log("按钮被点击了");
                }
            }
        };
        
        let myvue = new Vue(option);
         
    </script> 

多个函数间是逗号隔开。

vue报错的几种常见原因:

1.格式错误(比如多个函数没用逗号隔开)

2.根标签里写的所有变量(key)一定要和下面对应,即上面使用的东西下面必须有定义。但下面定义出来上面没有用是可以的。

一个简单的示例:点击按钮,改变标题文本:

    <body>
        <div id="mydiv">
            <h1>{{myval}}</h1>
           <input type="button" value="测试按钮" @click="myFun()" @mouseover="myFun2()" />
        </div> 
    </body>  
    <script>
​
        new Vue({
            el:"#mydiv",
            data:{
                myval:"测试"
            }, 
            methods:{
                myFun(){
                    console.log("按钮被点击了");
                    this.myval = "新测试";    //this指代生成这些函数的对象,即vue对象
                },
                myFun2(){
                    console.log("鼠标过来了");
                }
            }
        });
        
         
    </script> 

6.v-model

双向绑定

点击按钮,改变文本框的值,并且鼠标移过去读文本框的值。

    <body>
        <div id="mydiv">
            <h1>{{myval}}</h1>
            <input type="text" :value="mytest" />
           <input type="button" value="测试按钮" @click="myFun()" @mouseover="myFun2()" />
        </div> 
    </body>  
    <script>
​
        new Vue({
            el:"#mydiv",
            data:{
                myval:"测试",
                mytest:"abc123"
            }, 
            methods:{
                myFun(){
                    console.log("按钮被点击了");
                    this.mytest = "新测试";    
                },
                myFun2(){
                    console.log("鼠标过来了");
                    console.log(this.mytest);
                }
            }
        });
             
    </script> 

换一种做法:

自己在页面的文本框输入abc123456,鼠标飘到测试按钮,却并不是abc123。原因是做属性绑定做的是单向的绑定,即可以给元素赋值,但元素里的内容发生改变,而vue对象里mytest:"abc123"却并未发生改变。

这里用双向绑定:

    <body>
        <div id="mydiv">
            <h1>{{myval}}</h1>
            <input type="text" v-model="mytest" />
           <input type="button" value="测试按钮" @click="myFun()" @mouseover="myFun2()" />
        </div> 
    </body> 

双向绑定在不同的表单元素上用法不太一样。上面是文本框的使用。

以下是单选,多选,下拉列表的使用:

<body>
        <div id="mydiv">
           <input type="radio" value="1" v-model="gender" />男
           <input type="radio" value="2" v-model="gender" />女
           {{gender}}
           
           <br />
           <input type="checkbox" :value="1" v-model="hobby" />爬山   <!--value不加冒号,最后展现的是字符串 -->
           <input type="checkbox" :value="2" v-model="hobby" />游泳
           <input type="checkbox" :value="3" v-model="hobby" />开车
           {{hobby}}
           
           <br />
           <select v-model="area" @change="getVal()">
               <option value="110">北京</option>
               <option value="120">上海</option>
               <option value="130">深圳</option>
           </select>
           
        </div> 
    </body>  
    <script> 
​
        new Vue({
            el:"#mydiv",
            data:{
                gender:1 ,    //通过这个值设置哪个按钮选中
                hobby:[1,3],
                area:"120"
            },
            methods:{
                getVal(){
                    console.log(this.area);    //当选项改变时,将对应的value打印到控制台
                }
            }
        });
        
         
    </script> 

7.v-for

哪个元素需要重复生成,就在哪个元素上加v-for。

   <body>
        <div id="mydiv">
           <ul>
               <li v-for="mynews in newlist" >{{mynews.content}}</li>
           </ul>
           
        </div> 
    </body>  
    <script> 
​
        new Vue({
            el:"#mydiv",
            data:{
                newlist:[{"content":"新闻1"},{"content":"新闻2"},{"content":"新闻3"}]
            }
        });
         
    </script> 

页面输出:

  • 新闻1

  • 新闻2

  • 新闻3

如果有定值要写:

 <li v-for="mynews in newlist" >劲爆!!!{{mynews.content}}</li>

页面输出:

  • 劲爆!!!新闻1

  • 劲爆!!!新闻2

  • 劲爆!!!新闻3

其他几种遍历:

    <body>
        <div id="mydiv">
               <table border="1">
                   <tr>
                       <th>用户编号</th>
                       <th>用户名</th>
                       <th>手机号</th>
                   </tr>
                   <tbody>
                       <tr v-for="user in userlist">
                           <td>{{user.userId}}</td>
                           <td>{{user.userName}}</td>
                           <td>{{user.userPhone}}</td>
                       </tr>
                   </tbody>   
               </table> 
        </div> 
    </body>  
    <script> 
​
        new Vue({
            el:"#mydiv",
            data:{
                userlist:[{"userId":"001","userName":"小明","userPhone":"13838383838"},
                          {"userId":"002","userName":"小强","userPhone":"13838383838"},
                          {"userId":"003","userName":"小黄","userPhone":"13838383838"}]
            }
        });
        
         
    </script>

页面显示:

用户编号用户名手机号
001小明13838383838
002小强13838383838
003小黄13838383838

    <body>
        <div id="mydiv">
            <select v-model="myarea" >
                <option value="999">----请选择----</option>
                <option v-for="area in arealist" :value="area.areaId" >{{area.areaName}}</option>
            </select>
            {{myarea}}   
        </div> 
    </body>  
    <script> 
​
        new Vue({
            el:"#mydiv",
            data:{
                arealist:[{"areaId":"001","areaName":"北京"},
                          {"areaId":"002","areaName":"上海"},
                          {"areaId":"003","areaName":"深圳"}],
                myarea:"999"          
            }
        });
         
    </script> 

增加option选项,并且下拉列表最开始显示----请选择----

3.使用axios发送ajax请求 跨区处理

3.1使用axios发送ajax请求

页面加载结束后,想使用一些功能,vue提供了一些入口,这些入口称为钩子函数。

类似javaEE中的监听器。

vue允许在这些钩子函数里写代码。

vue中提供了一些钩子函数

如果页面加载结束做一些初始化设计,用mount比较合适。

示例:

新建vue钩子函数

    <body>
        <div id="mydiv">
             {{myval}} 
        </div> 
    </body>
    <script>
    
        new Vue({
            el:"#mydiv",
            data:{
                myval:"",     
            },
            methods:{
    
            },
            mounted(){
                console.log("页面加载后执行代码");
                //页面加载结束后 发ajax请求 取后台数据
                this.myval = "jack";  //页面加载结束后赋初始值
            },
            created(){
                console.log("vue对象创建出来了");
            }
        })
         
    </script> 

经常配合页面发ajax请求去后台取数据,取回数据,可直接给页面的元素赋值。

发ajax请求不使用jquery,而使用axios。

1.axios介绍

Axios 是一个基于 promise 的网络请求库,可以用于浏览器和 node.js

promise 对象是一个异步调用对象,ajax请求本身就是异步请求,需要配回调函数。

Axios 基于promise 对象封装ajax请求后,可以使用.then(表示成功的回调)和.catch(表示失败的回调)

在axios中文文档有详细的说明。

目前只需记住简化的方法:

// 向给定ID的用户发起请求
axios.get('/user?ID=12345')
  .then(function (response) {
    // 处理成功情况
    console.log(response);
  })
  .catch(function (error) {
    // 处理错误情况
    console.log(error);
  })
  .then(function () {
    // 总是会执行
  });

axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

打开BootCDN,在这里引入axios(也可下载它的js)

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="js/v2.6.10/vue.js" type="text/javascript" charset="UTF-8"></script>
        <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.27.2/axios.js"></script>
    </head>
    <body>
        <div id="mydiv">
             {{myval}} 
        </div> 
    </body>
    <script>
    
        new Vue({
            el:"#mydiv",
            data:{
                myval:"",     
            },
            methods:{
    
            },
            mounted(){
                console.log("页面加载后执行代码");
                this.myval = "jack";  
                console.log(axios); 
                axios.get("/xxx").then(function(ret){
                    console.log(ret);
                }).catch(function(err){
                    console.log(err); 
                })
            },
            created(){
                console.log("vue对象创建出来了");
            }
        }) 
         
    </script> 
</html>

运行,在开发者工具中打开network,可看到xxx对应的Type是xhr,表示的就是ajax的异步请求。

以上就发出了ajax异步请求。

接下来就是后台的处理:

新建项目day9_vueDemo

新建src.com.javasm.controller.AjaxServlet

@WebServlet("/myajax")
public class AjaxServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("请求进来了");
        String myVal = req.getParameter("myVal");
        myVal += "my dear!!!";
        resp.setContentType("application/json;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        writer.print("{\"returnMsg\":\""+myVal+"\"}");
        writer.flush();
        writer.close();
    }
}
​

启动服务器,访问http://localhost:8080/day9/myajax?myVal=jack

页面显示:{"returnMsg":"jackmy dear!!!"}

服务接口没问题。

将HBuilder中的vue钩子函数和day19_vue中的js复制到web包下:

现在使用的vue版本主要是v2.6.10,因为v3.2.8版本还没有全面铺开。

将vue钩子函数的地址xxx修改:(get方式,参数直接在后面拼)

/day9/myajax?myVal=rose

重新部署,运行,访问:http://localhost:8080/day9/vue钩子函数.html

前端代码里,发送ajax成功后,回调函数拿到后端返回的数据,然后把数据打印了出来。(console.log(ret);)

会发现,这里返回的数据和以前有些不同:

真正的数据其实在返回的json对象里的data,故应该用返回的数据再点data,才是返回的真正的数据,其他都是数据传输的一些相关参数。响应的写法上:

mounted() {
    console.log("页面加载后执行代码");
    console.log(axios);
    axios.get("/day9/myajax?myVal=rose").then(function(ret){
        console.log(ret.data);
     }).catch(function(err){
        console.log(err);
    })          
}

get方式的参数直接拼在请求地址后面即可。post方式的参数有些不同:

mounted() {
     console.log("页面加载后执行代码");
     console.log(axios);
     axios.post("/day9/myajax","myVal=rose").then(function(retdata){
        console.log(retdata.data);
     }).catch(function (err) {
        console.log(err);
     })
}

3.2跨区处理

前面是HBUdiler写好页面,复制到idea。idea的web端发ajax请求,idea的服务端再接收请求,发送响应。

能否直接从HBUdiler直接发Ajax请求,不用复制到idea去做?

在HBUdiler,将请求地址改为:/day9/myajax?myVal=rose,跳出的页面的控制台输出:

这是Hbuilder的404页面,在其network的Hearders可看到访问路径

访问地址不对。我们使用相对根路径是在当前服务器跳转,当前是HBUilder内嵌的一个小服务器,想访问的是Tomcat的服务器。

将HBUdiler请求地址改为:http://localhost:8080/day9/myajax?myVal=jack。因为之前页面输入该地址就能访问到Tomcat服务器。结果弹出的页面报错。

执行了一个不符合要求的跨域请求,即被CORS policy规则阻挡。

CORS policy叫同源策略,通过js发请求和在浏览器里发请求不同。使用js发请求要求同源,即ip,协议,端口一致。即同一个服务器随便取数据,不同服务器不能随便取人家的数据,人家不同意就取不到。出现跨域额访问,同源策略会阻止这种请求。

什么是跨域,http:// (协议) localhost:(地址) 8080(端口) 。这三个地方有一个不同就叫跨域。

刚才就是跨了端口。

是否允许跨域是由请求和响应报文体现的。每次发请求都会知道请求的来源地址(Origin)和

请求的目的地址(Host)。

处理是处理响应报文:

@WebServlet("/myajax")
public class AjaxServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /* 允许跨域的主机地址 */
        resp.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8848");
        /* 允许跨域的请求方法GET, POST, HEAD 等 */
        resp.setHeader("Access-Control-Allow-Methods", "*");
        /* 重新预检验跨域的缓存时间 (s) */
        resp.setHeader("Access-Control-Max-Age", "3600");
        /* 允许跨域的请求头 */
        resp.setHeader("Access-Control-Allow-Headers", "*");
        /* 是否携带cookie */
        resp.setHeader("Access-Control-Allow-Credentials", "true");
​
        System.out.println("请求进来了");
        String myVal = req.getParameter("myVal");
        myVal += "my dear!!!";
​
        resp.setContentType("application/json;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        writer.print("{\"returnMsg\":\""+myVal+"\"}");
        writer.flush();
        writer.close();
    }
}

允许跨域的主机地址从报错信息拿或者network的请求报文拿。

此时再用HBUilder访问就可以访问通了。

当你发送请求时,浏览器会自动发送一个method=option的请求,检测服务器返回的报文中是否包含允许跨域访问的响应头(域检请求)。在重写后台的方法时,是可以看到的:

@Override
    protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doOptions(req, resp);
    }

这个不要在服务端重写,浏览器会通过它发送域检请求。

总结:跨域请求何时产生?当前页面是服务器A,要访问的数据是服务器B时。

4.省市县级联

后端的代码不变。day5的AreaServlet,先配置项目。

然后在重写的service方法里加跨域访问的请求头:

        /* 允许跨域的主机地址 */
        resp.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8848");
        /* 允许跨域的请求方法GET, POST, HEAD 等 */
        resp.setHeader("Access-Control-Allow-Methods", "*");
        /* 重新预检验跨域的缓存时间 (s) */
        resp.setHeader("Access-Control-Max-Age", "3600");
        /* 允许跨域的请求头 */
        resp.setHeader("Access-Control-Allow-Headers", "*");
        /* 是否携带cookie */
        resp.setHeader("Access-Control-Allow-Credentials", "true");

在HBUilder里新建 省市县级联菜单.html:

①.从后台拿数据

引入vue,axios和qs对应的js

根标签还是id=mydiv的div标签。

在body标签加入省市县的下拉列表,放在根标签里。

在script标签新建vue对象。

先测试,在mounted()的axios里用post方法,并将参数设置,看是否能取到数据。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="js/v2.6.10/vue.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.26.0/axios.js"></script>
        <script src="https://cdn.bootcdn.net/ajax/libs/qs/6.10.3/qs.js"></script>
    </head>
    <body>
        <div id="mydiv">
            <select id="prov">
                <option disabled selected>------------请选择-------------</option>
            </select>省
            
            <select id="city">
                <option disabled selected>------------请选择-------------</option>     
            </select>市
            
            <select id="coun">
                <option disabled selected>------------请选择-------------</option>
            </select>县/区    
            
        </div>
    </body>
    <script>
    new Vue({
        el:"#mydiv",
        data:{
​
        },
        methods:{
            
        },
        mounted() {
            console.log("页面加载后取省数据");
            axios.post("http://localhost:8080/day5/getArea","areaid=00101").then(function(ret){
                console.log(ret.data);
            }).catch(function(err){
                console.log(err);
            })
        }
    })
    
    </script>
</html>

结果控制台输出:

页面加载后取省数据 并输出相应的数据。

②.将拿到的数据填到页面

就是在select标签里添option标签。

请选择所在option保留,不去管,在下面增加option。

返回的数据是省数组,要遍历,用v-for。遍历省数组也要在data里写明,初始值给一个空数组。测试数据一般先用假数据。将返回的数据填到空数组中。

请求先不发送,测试一下假数据是否好用。

<body>
        <div id="mydiv">
            <select id="prov">
                <option disabled selected>------------请选择-------------</option>
                <option v-for="prov in provlist" :value="prov.areaId">{{prov.areaName}}</option> 
            </select>省
            
            <select id="city">
                <option disabled selected>------------请选择-------------</option>     
            </select>市
            
            <select id="coun">
                <option disabled selected>------------请选择-------------</option>
            </select>县/区    
            
        </div>
    </body>
    <script>
    new Vue({
        el:"#mydiv",
        data:{
            provlist:[{areaId: "0010101",areaName: "金水区"},{areaId: "002",areaName: "黑背"}]
            
        },
        methods:{
            
        },
        mounted() {
            console.log("页面加载后取省数据");
    /*      axios.post("http://localhost:8080/day5/getArea","areaid=00101").then(function(ret){
                console.log(ret.data);
            }).catch(function(err){
                console.log(err);
            }) */
        }
    })
    
    </script>

省的下拉列表出现假数据,没问题。下一步填真数据。

真数据在retData:

mounted() {
            console.log("页面加载后取省数据");
        axios.post("http://localhost:8080/day5/getArea","areaid=00101").then(function(ret){
                console.log(ret.data.retData);
                this.provlist = ret.data.retData;
            }).catch(function(err){
                console.log(err);
            }) 

控制台打印出了真数据,但下拉列表没生效。

原因:这里this的指向改变了。axios对象和vue对象没关系,axios里的this指向window对象,指当前整个页面。

可以在外面建一个this,就可以在axios里使用了。

mounted() {
            console.log("页面加载后取省数据");
            let that = this;
            axios.post("http://localhost:8080/day5/getArea","areaid=00101").then(function(ret){
                console.log(ret.data.retData);
                that.provlist = ret.data.retData;
            }).catch(function(err){
                console.log(err);
            })  

运行后真实数据出现在了省的下拉列表中。

不过有更好的处理方式,直接写成箭头函数,替代匿名函数使用(类似之前的lomdar表达式):

使用箭头函数的好处:不是匿名函数,不改变箭头的指向

mounted() {
   console.log("页面加载后取省数据");
   axios.post("http://localhost:8080/day5/getArea","areaid=00101").then(ret=>{
   console.log(ret.data.retData);
   this.provlist = ret.data.retData; 
   }).catch(err=>{
      console.log(err);
})

给省做双向绑定。

当省改变,要知道当前选中的是哪个省,故在data里给出省编号的数据。省编号给到请选择的身上。

<body>
        <div id="mydiv">
            <select v-model="provCode" @change="changeCity()">
                <option :value="999" disabled selected>------------请选择-------------</option>
                <option v-for="prov in provlist" :value="prov.areaId">{{prov.areaName}}</option> 
            </select>省
            
            <select >
                <option disabled selected>------------请选择-------------</option>     
            </select>市
            
            <select >
                <option disabled selected>------------请选择-------------</option>
            </select>县/区    
            
        </div>
    </body>
    <script>
    new Vue({
        el:"#mydiv",
        data:{
            provCode:"999",
            provlist:[{areaId: "0010101",areaName: "金水区"},{areaId: "002",areaName: "黑背"}]
            
        },
        methods:{
            changeCity(){
                console.log(this.provCode);
            }
        },
        mounted() {
            console.log("页面加载后取省数据");
            axios.post("http://localhost:8080/day5/getArea","areaid=0").then(ret=>{
                console.log(ret.data.retData);
                this.provlist = ret.data.retData; 
            }).catch(err=>{
                console.log(err);
            })   
            
            
        }
    })
    
    </script>

接下来还是发请求取数据,还是先在data里建假数据。在市对应的select里加option。测试假数据:

<body>
        <div id="mydiv">
            <select v-model="provCode" @change="changeCity()">
                <option :value="999" disabled selected>------------请选择-------------</option>
                <option v-for="prov in provlist" :value="prov.areaId">{{prov.areaName}}</option> 
            </select>省
            
            <select >
                <option disabled selected>------------请选择-------------</option> 
                <option v-for="city in citylist" :value="city.areaId">{{city.areaName}}</option> 
            </select>市
            
            <select >
                <option disabled selected>------------请选择-------------</option>
            </select>县/区    
            
        </div>
    </body>
    <script>
    new Vue({
        el:"#mydiv",
        data:{
            provCode:"999",
            provlist:[{areaId: "0010101",areaName: "金水区"},{areaId: "002",areaName: "黑背"}],
            citylist:[{areaId: "001",areaName: "金水区2"},{areaId: "002",areaName: "黑背2"}]
            
        },
        methods:{
            changeCity(){
                console.log(this.provCode);
            }
        },
        mounted() {
            console.log("页面加载后取省数据");
            axios.post("http://localhost:8080/day5/getArea","areaid=0").then(ret=>{
                console.log(ret.data.retData);
                this.provlist = ret.data.retData; 
            }).catch(err=>{
                console.log(err);
            })   
            
            
        }
    })
    
    </script>

然后将真数据填入市的下拉列表:

<script>
    new Vue({
        el:"#mydiv",
        data:{
            provCode:"999",
            provlist:[{areaId: "0010101",areaName: "金水区"},{areaId: "002",areaName: "黑背"}],
            citylist:[]
            
        },
        methods:{
            changeCity(){
                console.log(this.provCode);
                axios.post("http://localhost:8080/day5/getArea","areaid="+this.provCode).then(ret=>{
                    console.log(ret.data.retData);
                    this.citylist = ret.data.retData; 
                }).catch(err=>{
                    console.log(err);
                }) 
                
                
            }
        },
        mounted() {
            console.log("页面加载后取省数据");
            axios.post("http://localhost:8080/day5/getArea","areaid=0").then(ret=>{
                console.log(ret.data.retData);
                this.provlist = ret.data.retData; 
            }).catch(err=>{
                console.log(err);
            })   
            
            
        }
    })
    
    </script>

换了省之后,市的下拉列表应该换成请选择。

<body>
        <div id="mydiv">
            <select v-model="provCode" @change="changeCity()">
                <option value="999" disabled selected>------------请选择-------------</option>
                <option v-for="prov in provlist" :value="prov.areaId">{{prov.areaName}}</option> 
            </select>省
            
            <select v-model="cityCode">
                <option value="999"  disabled selected>------------请选择-------------</option>    
                <option v-for="city in citylist" :value="city.areaId">{{city.areaName}}</option> 
            </select>市
            
            <select >
                <option disabled selected>------------请选择-------------</option>
            </select>县/区    
            
        </div>
    </body>
    <script>
    new Vue({
        el:"#mydiv",
        data:{
            provCode:"999",
            cityCode:"999",
            provlist:[{areaId: "0010101",areaName: "金水区"},{areaId: "002",areaName: "黑背"}],
            citylist:[]
            
        },
        methods:{
            changeCity(){
                console.log(this.provCode);
                this.cityCode = "999";   //省选项发生改变,市的下拉列表主动回到请选择
                axios.post("http://localhost:8080/day5/getArea","areaid="+this.provCode).then(ret=>{
                    console.log(ret.data.retData);
                    this.citylist = ret.data.retData; 
                }).catch(err=>{
                    console.log(err);
                }) 
                
                
            }
        },
        mounted() {
            console.log("页面加载后取省数据");
            axios.post("http://localhost:8080/day5/getArea","areaid=0").then(ret=>{
                console.log(ret.data.retData);
                this.provlist = ret.data.retData; 
            }).catch(err=>{
                console.log(err);
            })   
            
            
        }
    })
    
    </script>

至此省市的级联就做完了。

③.和县区的级联

同样先拿假数据测试:

<body>
        <div id="mydiv">
            <select v-model="provCode" @change="changeCity()">
                <option value="999" disabled selected>------------请选择-------------</option>
                <option v-for="prov in provlist" :value="prov.areaId">{{prov.areaName}}</option> 
            </select>省
            
            <select v-model="cityCode">
                <option value="999"  disabled selected>------------请选择-------------</option>    
                <option v-for="city in citylist" :value="city.areaId">{{city.areaName}}</option> 
            </select>市
            
            <select >
                <option disabled selected>------------请选择-------------</option>
                <option v-for="coun in counlist" :value="coun.areaId">{{coun.areaName}}</option> 
            </select>县/区    
            
        </div>
    </body>
    <script>
    new Vue({
        el:"#mydiv",
        data:{
            provCode:"999",
            cityCode:"999",
            provlist:[{areaId: "0010101",areaName: "金水区"},{areaId: "002",areaName: "黑背"}],
            citylist:[],
            counlist:[{areaId: "0010101",areaName: "金水区"},{areaId: "002",areaName: "黑背"}]
            
        },
        methods:{
            changeCity(){
                console.log(this.provCode);
                this.cityCode = "999";   //省选项发生改变,市的下拉列表主动回到请选择
                axios.post("http://localhost:8080/day5/getArea","areaid="+this.provCode).then(ret=>{
                    console.log(ret.data.retData);
                    this.citylist = ret.data.retData; 
                }).catch(err=>{
                    console.log(err);
                }) 
                
                
            }
        },
        mounted() {
            console.log("页面加载后取省数据");
            axios.post("http://localhost:8080/day5/getArea","areaid=0").then(ret=>{
                console.log(ret.data.retData);
                this.provlist = ret.data.retData; 
            }).catch(err=>{
                console.log(err);
            })   
            
            
        }
    })
    
    </script>

假数据没问题,清空假数据。当市改变时,发请求拿县区的真实数据,在city所在select加change事件:

<body>
        <div id="mydiv">
            <select v-model="provCode" @change="changeProv()">
                <option value="999" disabled selected>------------请选择-------------</option>
                <option v-for="prov in provlist" :value="prov.areaId">{{prov.areaName}}</option> 
            </select>省
            
            <select v-model="cityCode" @change="changeCity">
                <option value="999"  disabled selected>------------请选择-------------</option>    
                <option v-for="city in citylist" :value="city.areaId">{{city.areaName}}</option> 
            </select>市
            
            <select >
                <option disabled selected>------------请选择-------------</option>
                <option v-for="coun in counlist" :value="coun.areaId">{{coun.areaName}}</option> 
            </select>县/区    
            
        </div>
    </body>
    <script>
    new Vue({
        el:"#mydiv",
        data:{
            provCode:"999",
            cityCode:"999",
            provlist:[{areaId: "0010101",areaName: "金水区"},{areaId: "002",areaName: "黑背"}],
            citylist:[],
            counlist:[]
            
        },
        methods:{
            changeProv(){
                console.log(this.provCode);
                this.cityCode = "999";   //省选项发生改变,市的下拉列表主动回到请选择
                axios.post("http://localhost:8080/day5/getArea","areaid="+this.provCode).then(ret=>{
                    console.log(ret.data.retData);
                    this.citylist = ret.data.retData; 
                }).catch(err=>{
                    console.log(err);
                }) 
            },
            changeCity(){
                console.log(this.cityCode);
                axios.post("http://localhost:8080/day5/getArea","areaid="+this.cityCode).then(ret=>{
                    console.log(ret.data.retData);
                    this.counlist = ret.data.retData; 
                }).catch(err=>{
                    console.log(err);
                }) 
            }
            
        },
        mounted() {
            console.log("页面加载后取省数据");
            axios.post("http://localhost:8080/day5/getArea","areaid=0").then(ret=>{
                console.log(ret.data.retData);
                this.provlist = ret.data.retData; 
            }).catch(err=>{
                console.log(err);
            })   
            
            
        }
    })
    
    </script>

当市的选项发生改变时,县区的选项变为请选择:

<body>
        <div id="mydiv">
            <select v-model="provCode" @change="changeProv()">
                <option value="999" disabled selected>------------请选择-------------</option>
                <option v-for="prov in provlist" :value="prov.areaId">{{prov.areaName}}</option> 
            </select>省
            
            <select v-model="cityCode" @change="changeCity">
                <option value="999"  disabled selected>------------请选择-------------</option>    
                <option v-for="city in citylist" :value="city.areaId">{{city.areaName}}</option> 
            </select>市
            
            <select v-model="counCode">
                <option value="999" disabled selected>------------请选择-------------</option>
                <option v-for="coun in counlist" :value="coun.areaId">{{coun.areaName}}</option> 
            </select>县/区    
            
        </div>
    </body>
    <script>
    new Vue({
        el:"#mydiv",
        data:{
            provCode:"999",
            cityCode:"999",
            counCode:"999",
            provlist:[{areaId: "0010101",areaName: "金水区"},{areaId: "002",areaName: "黑背"}],
            citylist:[],
            counlist:[]
            
        },
        methods:{
            changeProv(){
                console.log(this.provCode);
                this.cityCode = "999";   //省选项发生改变,市的下拉列表主动回到请选择
                axios.post("http://localhost:8080/day5/getArea","areaid="+this.provCode).then(ret=>{
                    console.log(ret.data.retData);
                    this.citylist = ret.data.retData; 
                }).catch(err=>{
                    console.log(err);
                }) 
            },
            changeCity(){
                console.log(this.cityCode);
                this.counCode = "999";   
                axios.post("http://localhost:8080/day5/getArea","areaid="+this.cityCode).then(ret=>{
                    console.log(ret.data.retData);
                    this.counlist = ret.data.retData; 
                }).catch(err=>{
                    console.log(err);
                }) 
            }
            
        },
        mounted() {
            console.log("页面加载后取省数据");
            axios.post("http://localhost:8080/day5/getArea","areaid=0").then(ret=>{
                console.log(ret.data.retData);
                this.provlist = ret.data.retData; 
            }).catch(err=>{
                console.log(err);
            })   
            
            
        }
    })
    
    </script>

当省选项改变,县区的选项也需要变为请选择,且选项也要清空。

changeProv(){
                console.log(this.provCode);
                this.cityCode = "999";   //省选项发生改变,市的下拉列表主动回到请选择
                this.counCode = "999";   //省选项发生改变,县区的下拉列表主动回到请选择
                this.counlist = [];
                axios.post("http://localhost:8080/day5/getArea","areaid="+this.provCode).then(ret=>{
                    console.log(ret.data.retData);
                    this.citylist = ret.data.retData; 
                }).catch(err=>{
                    console.log(err);
                }) 
            }

总结:使用vue要抛弃掉找元素,改属性,自己页面渲染的思想。这些vue框架都帮着做了,我们所要关注的就是数据怎么去变。

④.qs.js

上面发送参数时用的是比较原始的url拼接的格式:

axios.post("http://localhost:8080/day5/getArea","areaid=0")

以前用jquery时可用json格式:

axios.post("http://localhost:8080/day5/getArea",{"areaid":"0"})

这样去写,参数并没有传过去。原因:使用axios方式传数据,如果是json格式,会用json格式原封不动的传入后台。

后台不使用工具就解析不出来。

若后台不用工具,前台就想发json格式数据,就要用到qs,一个把json对象转成字符串拼接格式的工具。

axios.post("http://localhost:8080/day5/getArea",window.Qs.stringify({"areaid":"0"}))

最终的代码如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="js/v2.6.10/vue.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.26.0/axios.js"></script>
        <script src="https://cdn.bootcdn.net/ajax/libs/qs/6.10.3/qs.js"></script>
    </head>
    <body>
        <div id="mydiv">
            <select v-model="provCode" @change="changeProv()">
                <option value="999" disabled selected>------------请选择-------------</option>
                <option v-for="prov in provlist" :value="prov.areaId" >{{prov.areaName}}</option>
            </select>省
            
            <select v-model="cityCode" @change="changeCity">
                <option value="999" disabled selected>------------请选择-------------</option>
                <option v-for="city in citylist" :value="city.areaId" >{{city.areaName}}</option>   
            </select>市
            
            <select v-model="counCode">
                <option value="999" disabled selected>------------请选择-------------</option>
                <option v-for="coun in counlist" :value="coun.areaId" >{{coun.areaName}}</option>
            </select>县/区    
            
        </div>
    </body>
    <script>
    new Vue({
        el:"#mydiv",
        data:{
            provCode:"999",
            cityCode:"999",
            counCode:"999",
            provlist:[{areaId: '001', areaName: '河南2'},{areaId: '002', areaName: '河北2'}],
            citylist:[],
            counlist:[]
​
        },
        methods:{
            changeProv(){
                console.log(this.provCode);
                this.cityCode = "999";
                this.counCode = "999";
                this.counlist = [];
                axios.post("http://localhost:8080/day5/getArea","areaid="+this.provCode)
                .then(ret=>{
                    //使用箭头函数 替代匿名函数  
                    //箭头函数不改变this的指向 可以直接使用到vue对象
                    console.log(ret.data.retData);
                    this.citylist = ret.data.retData;
                }).catch(err=>{
                    console.log(err);
                })
​
            },
            changeCity(){
                console.log(this.cityCode);
                this.counCode = "999";
                axios.post("http://localhost:8080/day5/getArea","areaid="+this.cityCode)
                .then(ret=>{
                    //使用箭头函数 替代匿名函数  
                    //箭头函数不改变this的指向 可以直接使用到vue对象
                    console.log(ret.data.retData);
                    this.counlist = ret.data.retData;
                }).catch(err=>{
                    console.log(err);
                })
                
            }
        },
        mounted() {
            console.log(window.Qs.stringify({"areaid":"0"}));
            console.log("页面加载后取省数据");
            //console.log(this);
            //let that = this;
            axios.post("http://localhost:8080/day5/getArea",window.Qs.stringify({"areaid":"0"}))
            .then(ret=>{
                //使用箭头函数 替代匿名函数  
                //箭头函数不改变this的指向 可以直接使用到vue对象
                console.log(ret.data.retData);
                this.provlist = ret.data.retData;
            }).catch(err=>{
                console.log(err);
            })
            /* .then(function(ret){
                console.log(ret.data.retData);
                console.log(this);
                that.provlist = ret.data.retData;
                
            }).catch(function(err){
                console.log(err);
            }) */
                    
        }
    })
    
    </script>
</html>
​
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值