Vue2笔记

初始Vue

const vm = new Vue({
            el:"#box",//el表示elements
            data:{   //data用于存储数据,数据仅供el里面指定的容器所用,值暂时写成对象的形式,往后可能会用到函数的形式                               //el,data是这个vue实例的配置对象
                name:",我是xxx"
            }
        });

单向数据绑定和双向数据绑定

<!-- <div id="box">
        单向数据绑定:<input type="text" v-bind:value="name" />
        双向数据绑定:<input type="text" v-model:value="name" />
    </div> -->
                <!--简写-->
                <div id="box">
                    单向数据绑定:<input type="text" :value="name" />
                    双向数据绑定:<input type="text" v-model="name" />
                </div>
<!-- v-model 只应用在表单元素上(输入类元素 例:input selected等)-->
​

理解MVVM模型

<!--

MVVM模型

1.M:模型(Model):data中的数据

2.V:视图(View):模板代码

3.VM:视图模型(ViewModel):Vue实例

观察发现:

1.data中所有的属性,最后都出现在了vm身上

2.vm身上所有的属性及Vue原型上所有属性,在Vue模板中都可以直接使用。

-->

defineProperty函数的认识

<script type="text/javascript">
        var number = 18;
        var person = {
            name:"张三",
            sex:"男"
        }
        
                              //这里的参数age的意思是,往对象person中添加一个age属性
        Object.defineProperty(person,'age',{
            //value:18, //如果使用这个函数添加属性的话,你修改这个属性的话,那么是不起作用的
            //enumerable:true, //控制属性是否枚举(遍历),默认值是false
            //writable:true, //控制属性是否可以被修改,默认值是false
            //configurable:true //控制属性是否被删除,默认值为false
​
​
            //当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
            get(){
                console.log("有人读取了age属性了")
                return number;
            },
            //当有人修改person的age属性时,set函数(setter)就会被调用,且返回值就是age的值
            set(value){
                console.log("有人修改了age属性了,且值是",value)
                number = value
            }
        })
        console.log(person);
    </script>

非单文件组件

<!--
        Vue中使用组件的三大步骤:
            一、定义组件
            二、注册组件 在vm中写compents:{}
            三、使用组件(写组件标签)在DOM元素上面写
​
        一、如何定义一个组件?
            使用Vue.extend({})创建,其中和new Vue({})有些区别
            区别如下:
                1.el不要写,为什么? —— 最终所有的组件都要经过一个vm管理,由vm中的el决定服务哪个容器
                2.data中必须写成函数,为什么? —— 避免组件被复用时,数据存在引用关系.
            备注:使用template可以配置组件结构
​
        二、如何注册组件
            1.局部注册:靠new Vue的时候传入到components:{}
            2.全部注册:靠Vue.component('组件名',组件)
​
        几个注意点:
            1.关于组件名:
                一个单词组成:
                    第一种写法(首字母小写)school
                    第二种写法(首字母大写)School
​
                多个单词组成:
                    第一种写法(kebab-case命名):my-school
                    第二种写法(CamelCase命名):MySchool(需要vue脚手架支持)
                备注:
                    (1).组件名尽可能回避HTML中已有的元素名称。例如:h2,H2等都不行。
​
            2.关于组件标签:
                第一种写法:<school></school>
                第二种写法:<school>
                备注:不用使用脚手架时,<school/>会导致后续组件不能渲染
​
            3.一个简写的方式:
                    const school = Vue.extend({}) 可简写成: const school = {}
    -->

非但文件组件嵌套

<body>
    <!--
        Vue中使用组件的三大步骤:
            一、定义组件
            二、注册组件
            三、使用组件(写组件标签)
​
    -->
    <div id="root">
        <!--第三步,写组件标签调用-->
        <hello></hello>
​
    </div>
    <script type="text/javascript">
        //要把被管理的组件放在要管理他的组件上面,把student组件归于school管理,在管理student的组件里面注册和调用student
        const student = Vue.extend({
            template:`
                <div>
                    <h4>{{name}}</h4>
                    <h4>{{age}}</h4>      
                </div>
            `,
            data(){
                 return{
                    name:"黄健聪",
                    age:18
                }
            }
        })
        //第一步,-创建组件
        const school = Vue.extend({
            template:`
                <div>
                    <h4>{{name}}</h4>
                    <h4>{{address}}</h4>
                    <student></student>      
                </div>
            `,
            data(){
                 return{
                    name:"广东机电",
                    address:"白云区"
                }
            },
            components:{
                student
            }
        })
        const app = Vue.extend({
            template:`
            <div>
                <school></school>    
            </div>
            `,
            components:{
                school
            }
        })
        const vm = new Vue({
            template:`
            <div>
                <hello></hello>
                <app></app>
            </div>  
            `,
            el:"#root",
            //第二步,注册组件
            components:{
                hello,
                app
            }
        })
    </script>
</body>

过滤器

<body>
    <div id="root">
        计算属性:{{ftmTime}}<br/>
        方法属性:{{methodsTime()}}
    </div>
​
    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                time:1646660802602
            },
            computed:{
                ftmTime(){
                    return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
                }
            },
            methods:{
                methodsTime(){
                    //day.js 是一个轻量的处理时间和日期的 JavaScript 库,需要在终端下载                                   npm i dayjs
                    return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
                }
            }
        })
        
    </script>
</body>

计算属性

姓名案例-插值语法实现

<body>
    <!--准备一个容器-->
    <div id="root">
        姓:<input type="text" v-model="firstName"  /><br/><br/>
        名:<input type="text" v-model="lastName"  /><br/><br/>
        全名:<span>{{firstName.slice(0,3)}}-{{lastName}}</span><!--slice():切割字符串保留三位,三位之后不再显示出来-->
    </div>
​
    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                firstName:"张",
                lastName:"三"
            }
        })
    </script>
</body>

姓名案例-计算属性方法实现

<body>
    <!--准备一个容器-->
    <div id="root">
        姓:<input type="text" v-model="firstName"  /><br/><br/>
        名:<input type="text" v-model="lastName"  /><br/><br/>
        全名:<span>{{fullName}}</span>
    </div>
​
    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                firstName:"张",
                lastName:"三"
            },
            computed:{
                fullName:{
                    get(){
                        console.log("get被调用了");
                        return this.firstName + "-" + this.lastName;
                    },
                    set(value){
                        console.log("有人在修改名字");
                        var arr = value.split("-");
                        this.firstName = arr[0];
                        this.lastName =  arr[1];
                    }
                }
            }
        })
    </script>
</body>

姓名案例-methods方法实现

<body>
    <!--准备一个容器-->
    <div id="root">
        姓:<input type="text" v-model="firstName"  /><br/><br/>
        名:<input type="text" v-model="lastName"  /><br/><br/>
        全名:<span>{{fullName()}}</span>
    </div>

    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                firstName:"张",
                lastName:"三"
            },
            methods:{
                fullName(){
                    return this.firstName + "-" + this.lastName;
                }
            }
        })
    </script>
</body>

姓名案例-watch语法实现

<body>
    <!--准备一个容器-->
    <div id="root">
        姓:<input type="text" v-model="firstName"  /><br/><br/>
        名:<input type="text" v-model="lastName"  /><br/><br/>
        全名:<span>{{fullName}}</span>
    </div>

    <!--
        computed和watch之间的区别:
            1.computed能完成的功能,watch都可以完成
            2.watch能完成的功能,computed不一定能完成 。例如watch可以进行异步操作(setTimeout()定时器)
                两个重要的小案例:
                    1.所被Vue管理的函数,最好写成普通函数,这样this的指向vm或组件实例对象。
                    2.所有不被Vue所管理的函数(定时器的回调函数,ajax的回调函数等 ,Promise的回调函数),最好写成箭头函数。
    -->

    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                firstName:"张",
                lastName:"三",
                fullName:"张-三"
            },
            /**
                1.监视属性
                    1.初始化要被监视的对象
                    2.写出要监视的对象的相关data里面要监视的对象
            **/
           watch:{
            //1.写出要监视的对象的相关data里面要监视的对象
            firstName(newValue){
                //在data里面初始化要被监视的对象
                this.fullName = newValue + "-" +this.lastName;
            },
            /*setTimeout()   不被Vue所管理的回调函数,所以用箭头函数去写*/
            firstName(newValue){
                //在data里面初始化要被监视的对象
                setTimeout(()=>{
                    this.fullName = newValue + "-" +this.lastName;
                },2000)
            },
            lastName(newValue){
                //在data里面初始化要被监视的对象
                this.fullName = this.firstName + "-" +newValue;
            },
           }
        })
    </script>
</body>

监视属性

天气案例-监视属性

<body>
    <div id="root">
        <h3>今天天气是{{info}}</h3><!--用计算属性-->
        <button @click="changeWeather">切换天气</button>
    </div>

    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                isHot:true
            },
            methods:{
                changeWeather(){
                   this.isHot = !this.isHot; 
                }
            },
            // watch:{
            //     info:{
            //         immediate:true,//初始化,在页面加载时监视一次,让handler()调用一次。
            //         handler(newValue,oldValue){//当info发生改变时调用
            //             console.log("info的值被修改了",newValue,oldValue)
            //         }
            //     }
            // },
            computed:{
                info(){
                    return this.isHot? '炎热' : '凉爽'    
                },
            }
        })
        vm.$watch('info',{
            immediate:true,
            handler(newValue,oldValue){
                         console.log("info的值被修改了",newValue,oldValue)
                     }
        })
    </script>
</body>

天气案例-监视属性简写

<body>
    <div id="root">
        <h3>今天天气是{{info}}</h3><!--用计算属性-->
        <button @click="changeWeather">切换天气</button><br /><br />
        <h3>{{numbers.a}}</h3>
        <button @click="numbers.a++">点击a+1</button><br /><br />
        <h3>{{numbers.b}}</h3><br /><br />
        <button @click="numbers.b++">点击b+1</button>
    </div>

    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                isHot:true,
                numbers:{
                    a:1,
                    b:1
                }
            },
            methods:{
                changeWeather(){
                   this.isHot = !this.isHot; 
                }
            },
            //完整写法
            /*
            watch:{
                info:{
                    immediate:true,
                    handler(newValue,oldValue){
                        console.log("info的值被修改了",newValue,oldValue)
                    }
                }   
            },*/
            /*watch简写*/
            /*watch:{
                info(newValue,oldValue){
                    console.log("info的值被修改了",newValue,oldValue
                    )
                }
            },*/
            computed:{
                info(){
                    return this.isHot? '炎热' : '凉爽'    
                },
            }
        })
        /*$watch完整版*/
        // vm.$watch('info',{
        //     immediate:true,
        //     handler(newValue,oldValue){
        //                  console.log("info的值被修改了",newValue,oldValue)
        //              }
        // })

         /*$watch简写*/
         vm.$watch('info',function(newValue,oldValue){
            console.log("info的值被修改了",newValue,oldValue)
         })
    </script>
</body>

天气案例-深度监视属性

<body>
    <div id="root">
        <h3>今天天气是{{info}}</h3><!--用计算属性-->
        <button @click="changeWeather">切换天气</button><br /><br />
        <h3>{{numbers.a}}</h3>
        <button @click="numbers.a++">点击a+1</button><br /><br />
        <h3>{{numbers.b}}</h3><br /><br />
        <button @click="numbers.b++">点击b+1</button>
    </div>

    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                isHot:true,
                numbers:{
                    a:1,
                    b:1
                }
            },
            methods:{
                changeWeather(){
                   this.isHot = !this.isHot; 
                }
            },
            watch:{
                info:{
                    immediate:true,
                    handler(newValue,oldValue){
                        console.log("info的值被修改了",newValue,oldValue)
                    }
                },
                //因为是更深度的监视,所以要加个引号。监视多级。
                //这个监视只是在点击a+的时候才会调用,要是想点击b的时候也被监视的话,同理
                // 'numbers.a':{
                //     handler(){
                //         console.log("a被点击,慢慢的增大了")
                //     }
                // },
                //如果想在点击对象里面的每一个属性都发生监视的话,那就加个deep:true。加了之后,你点击该对象的任一属性,那么里面的属性都会被调用
                numbers:{
                    deep:true,//开启深度监视。
                    handler(){
                        console.log("numbers改变了")
                    }
                },
            },
            computed:{
                info(){
                    return this.isHot? '炎热' : '凉爽'    
                },
            }
        })
        // vm.$watch('info',{
        //     immediate:true,
        //     handler(newValue,oldValue){
        //                  console.log("info的值被修改了",newValue,oldValue)
        //              }
        // })
    </script>
</body>

天气案例

<body>
    <div id="root">
        <h3>今天天气是{{info}}</h3><!--用计算属性-->
        <button @click="changeWeather">切换天气</button>
    </div>

    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                isHot:true
            },
            methods:{
                changeWeather(){
                   this.isHot = !this.isHot; 
                }
            },
            computed:{
                info(){
                    return this.isHot? '炎热' : '凉爽'    
                },
                
            }
        })
    </script>
</body>

列表过滤

</head>
<body>
    <!--
        v-for指令
            1.用于展示列表数据
            2.语法:v-for="{item,index} in xxx" :key="yyy"
            3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
    -->
    <div id="root">
        <input type="text" v-model="keyWord" />
        <h2>列表渲染(遍历)</h2>
        <ul>
            <li v-for="p in fieArr" :key="p.id">
                {{p.name}}-{{p.age}}
            </li>
        </ul>
    </div>

    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                keyWord:"",
                Arr:[
                    {id:001,name:"周冬雨",age:"18"},
                    {id:002,name:"马冬梅",age:"19"},
                    {id:003,name:"周杰伦",age:"20"},
                    {id:004,name:"温兆伦",age:"21"}
                ],
                fieArr:[],
            },   
            //用监视的方法来改变要筛选的值,然后在收取出来    
            watch:{
                 //要监视的对象,那么这里要监视keyWord,因为keyWord变化带动整个筛选
                keyWord:{
                    immediate:true,
                    handler(value){
                        this.fieArr = this.Arr.filter((p)=>{
                            return p.name.indexOf(value) !==-1;
                        })
                    }
                }  
            } 
        })
    </script>
</body>

列表过滤computed

<body>
    <!--
        v-for指令
            1.用于展示列表数据
            2.语法:v-for="{item,index} in xxx" :key="yyy"
            3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
    -->
    <div id="root">
        <input type="text" v-model="keyWord" />
        <h2>列表渲染(遍历)</h2>
        <ul>
            <li v-for="p in fieArr" :key="p.id">
                {{p.name}}-{{p.age}}
            </li>
        </ul>
    </div>

    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                keyWord:"",
                Arr:[
                    {id:001,name:"周冬雨",age:"18"},
                    {id:002,name:"马冬梅",age:"19"},
                    {id:003,name:"周杰伦",age:"20"},
                    {id:004,name:"温兆伦",age:"21"}
                ],
            },       
            computed:{
                fieArr(){
                    return this.Arr.filter((p)=>{
                            return p.name.indexOf(this.keyWord) !==-1
                        }) 
                }
            }
        })
    </script>
</body>

列表排序

<body>
    <!--
        v-for指令
            1.用于展示列表数据
            2.语法:v-for="{item,index} in xxx" :key="yyy"
            3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
    -->
    <div id="root">
        <input type="text" v-model="keyWord" />
        <h2>列表渲染(遍历)</h2>
        <ul>
            <li v-for="p in fieArr" :key="p.id">
                {{p.name}}-{{p.age}}
            </li>
        </ul>
        <button type="button" @click="sortType=0">原顺序</button>
        <button type="button" @click="sortType=1">降序</button>
        <button type="button" @click="sortType=2">升序</button>
    </div>

    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                sortType:0,
                keyWord:"",
                Arr:[
                    {id:001,name:"周冬雨",age:"18"},
                    {id:002,name:"马冬梅",age:"19"},
                    {id:003,name:"周杰伦",age:"20"},
                    {id:004,name:"温兆伦",age:"21"}
                ],
            },       
            computed:{
                fieArr(){
                    const type =  this.Arr.filter((p)=>{
                            return p.name.indexOf(this.keyWord) !==-1
                        })
                        if(this.sortType){
                            type.sort((p1,p2)=>{
                                return this.sortType ==1 ?p2.age-p1.age : p1.age-p2.age
                            })
                        } 
                        return type;
                }
            }
        })
    </script>
</body>

列表渲染

<body>
    <!--
        v-for指令
            1.用于展示列表数据
            2.语法:v-for="{item,index} in xxx" :key="yyy"
            3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
    -->
    <div id="root">
        <!--遍历数组-->
        <h2>人员列表(遍历数组)</h2>
        <ul>
            <!-- <li v-for="p in Arr" :key="id">
                {{p.name}}-{{p.age}}
            </li> -->
            <!--括号里面的第一个参数是遍历数组的值,第二个参数是索引值-->
            <!-- <li v-for="(p,index) in Arr" :key="id">
                {{p.name}}-{{p.age}}-{{index}}
            </li> -->
        </ul>

        <!-- <h2>汽车列表(遍历对象)</h2>
        <ul>
            <li v-for="(p,index) in car" :key="index">
                {{p}}-{{index}}
            </li>
        </ul> -->

        <!-- <h2>字符串列表(遍历字符串)</h2>
        <ul>
            <li v-for="(p,index) in str" :key="index">
                {{p}}-{{index}}
            </li>
        </ul> -->

        <h2>数字列表(遍历数字)</h2>
        <ul>
            <li v-for="(p,index) in 5" :key="index">
                {{p}}-{{index}}
            </li>
        </ul>
    </div>

    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                Arr:[
                    {id:001,name:"黄健聪",age:"18"},
                    {id:002,name:"张晓靖",age:"18"},
                    {id:003,name:"张国荣",age:"18"}
                ],
                car:{
                    name:"宝马",
                    price:"50万"
                },
                str:"hello"
            }    
        })
    </script>
</body>

key的作用和原理

<body>
    <!--
        1.index作为key可能会引发的问题:
            (1).若对数据进行:逆序添加,逆序删除等破坏顺序操作:
                    会产生没有必要的真实的DOM更新 ===> 界面效果没问题,但效率低

            (2).如果结构中还包含输入类的DOM:
                    会产生错误DOM更新 ===>界面有问题

        2.开发中然后选中key?:
            (1).最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号,学号等唯一值。
            (2).如果不存在对象数据的逆序添加,逆序删除等破坏顺序操作,仅用于渲染例表用于展示,使用index作为key是没有问题的。
    -->
    <div id="root">
        <h2>人物列表(遍历人物)</h2>
        <ul>
            <li v-for="p in Persons" :key="p.id">
                {{p.name}}-{{p.age}}
                <input type="text" />
            </li>
        </ul>
        <button @click="add">点我添加老刘</button>
    </div>

    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                Persons:[
                    {id:001,name:"黄健聪",age:"18"},
                    {id:002,name:"张晓靖",age:"18"},
                    {id:003,name:"张国荣",age:"18"}
                ],
            },
            methods: {
                add(){
                    var p = {id:004,name:"老刘",age:"40"}
                    this.Persons.unshift(p);
                }
            },    
        })
    </script>
</body>

生命周期

<body>
    <!--
        生命周期:
            1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
            2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数
            3.生命周期函数的名字不可更改,但哈桑农户䣌具体内容是程序员根据需求编写的
            4.生命周期函数中的this指向的是vm 或者 组件实例对象
    -->
    <div id="root">
        <h2 :style="{opacity}">今天继续学习Vue</h2>
    </div>

    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                opacity:1
            },
            //生命周期挂载
            //Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
            mounted(){
                setInterval(()=>{
                    this.opacity-=0.1;
                    if(this.opacity <=0) this.opacity=1
                },100)
            },
        })
    </script>
</body>

收集表单数据

<body>
    <!--
        收集表单数据:
            若:<input type="text" />,则v-model收集的是value值,用户输入的就是value值。
            若:<input type="radio" />,则v-model收集的是value值,且要给标签配置value值。
            若:<input type="checkbox" />
                            1.没有配置value属性的input,那么收集的就是checked(勾选 or 未勾选,是布尔值)
                            2.配置value属性的input
                                (1).v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
                                (2).v-model的初始值是数组,那么收集的就是value组成的数组
                            
                                备注:v-model的三个修饰符:
                                    lazy:失去焦点再收集数据
                                    number:输入字符串转为有效的数字
                                    trim:输入首尾空格过滤
    -->
    <div id="root">
        <form @submit.prevent="demo">
            <!--trim 去除字符串前后的空格-->
            账号:<input type="text" v-model.trim="userInfo.name" /><br /><br />
            密码:<input type="password" v-model="userInfo.name" /><br /><br />
            年龄:<input type="number" v-model.number="userInfo.age" /><br /><br />
            性别:<!--单选一个的话,要用同一个name属性,这样子就可以实现单选的效果-->
            男<input type="radio" name="sex" v-model="userInfo.sex" value="male" />
            女<input type="radio" name="sex" v-model="userInfo.sex" value="female" /><br /><br />
            爱好:
            学习:<input type="checkbox" v-model="userInfo.hobby" value="study" />
            打游戏:<input type="checkbox" v-model="userInfo.hobby" value="game" />
            吃饭:<input type="checkbox" v-model="userInfo.hobby" value="food" /><br /><br />
            所属校区:
            <select v-model="userInfo.city">
                <option value="">请选择校区</option>
                <option value="beijing">北京</option>
                <option value="shanghai">上海</option>
                <option value="shenzhen">深圳</option>
                <option value="guangdong">广东</option>
            </select>
            <br /><br />
            其他信息:
            <textarea v-model="userInfo.other"></textarea><br /><br />
            <!--lazy 表示当该输入失去焦点的时候再收集输入的数据-->
            <input type="checkbox" v-model.lazy="userInfo.agree" />阅读并接受<a href="www.baidu.com">《注意条款》</a>
            <button>提交</button>
        </form>
    </div>

    <script src="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                userInfo:{
                name:"",
                age:"",
                sex:"",
                hobby:[],
                city:"",
                other:"",
                agree:""
                }
                
            },
            methods: {
                demo(){
                   alert("1")
                }
            },
        })
    </script>
</body>

条件渲染

<body>
    <!--
        条件渲染
            1.v-if
                写法:
                    (1).v-if = "表达式"
                    (2).v-else-if = "表达式"
                    (3).v-else = "表达式"
                适用于:切换频率较低的场景
                特点:不展示的DOM元素未被移除
                注意:v-if可以和v-else-if、v-else一起使用,但要求结构不能被"打断"。
​
            2.v-show
                写法:v-show="表达式"
                适用于:切换频率较高的场景。
                特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
            
            3.备注:使用v-if时,元素可能无法获取到,而使用v-show一定可以获取到
    -->
    <div id="root">
        <h2>当前的n值是{{n}}</h2>
        <button @click="n++">点我+1</button>
        <!--使用v-show做条件渲染-->
        <!--<h2 v-show="false">大家好,我的名字叫{{name}}</h2>-->
        <!--<h2 v-show="1 === 1">大家好,我的名字叫{{name}}</h2>-->
​
        <!--使用v-if做条件渲染-->
        <!--<h2 v-if="false">大家好,我的名字叫{{name}}</h2>-->
        <!--<h2 v-if="1 === 1">大家好,我的名字叫{{name}}</h2>-->
​
        <!--v-else和else-if-->
        <div v-if="n === 1">Angular</div>
        <div v-else-if="n === 2">React</div>
        <div v-else-if="n === 3">Vue</div>
​
        <!--template只能与v-if配合使用
                这样子可以方便一下子显示相同的条件出来,也不破坏控制器里面的完整结构
        -->
        <template v-if="n === 1">
            <h3>你好</h3>
            <h3>黄健聪</h3>
            <h3>张晓靖</h3>
        </template>
    </div>
​
    <script type="text/javascript">
        const vm  = new Vue({
            el:"#root",
            data:{
                name:"黄健聪",
                n:0,
            }
        })
    </script>
</body>

自定义函数

自定义函数

<body>
    <!--
        需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍
        需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点
    -->
    <div id="root">
        <h3>当前的n值是</nbsp><span v-text="n"></span></h3>
        <h3>当前的n值是</nbsp><span v-big="n"></span></h3>
        <button @click="n++">点我+1</button>
    </div>
​
    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                n:1
            },
            directives:{
                big(element,bangding){
                    element.innerText = bangding.value*10
                }
            }
        })
    </script>
</body>

自定义函数2

<body>
    <!--
        需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍
        需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点
    -->
    <div id="root">
        <h3>当前的n值是</nbsp><span v-text="n"></span></h3>
        <h3>当前的n值是</nbsp><span v-big="n"></span></h3>
        <h3>当前的n值是</nbsp><input v-fbind:value="n"></input></h3>
        <button @click="n++">点我+1</button>
    </div>

    <script type="text/javascript">
        const vm = new Vue({
            el:"#root",
            data:{
                n:1
            },
            directives:{
                big(element,bangding){
                    element.innerText = bangding.value*10
                },
                fbind:{
                    //指令与元素成功绑定时(一上来)
                    bind(element,bangding){
                        element.value = bangding.value;
                    },
                    //指令所在元素被插入页面时
                    inserted(element,bangding){
                        element.focus();
                    },
                    //指令所在的模板被重新解析时
                    update(element,bangding) {
                        element.value = bangding.value;
                    },
                }
            }
        })
    </script>
</body>

自定义函数全局版

<body>
    <!--
        需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍
        需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点
    -->
    <div id="root">
        <h3>当前的n值是</nbsp><span v-text="n"></span></h3>
        <h3>当前的n值是</nbsp><span v-big="n"></span></h3>
        <h3>当前的n值是</nbsp><input v-fbind:value="n"></input></h3>
        <button @click="n++">点我+1</button>
    </div>

    <div id="root2">
        <h3>当前的n值是</nbsp><input v-fbind:value="x"></input></h3>
    </div>

    <script type="text/javascript">
        //全局写法
        Vue.directive('fbind',{
                    //指令与元素成功绑定时(一上来)
                    bind(element,bangding){
                        element.value = bangding.value;
                    },
                    //指令所在元素被插入页面时
                    inserted(element,bangding){
                        element.focus();
                    },
                    //指令所在的模板被重新解析时
                    update(element,bangding) {
                        element.value = bangding.value;
                    },
                })
        const vm = new Vue({
            el:"#root",
            data:{
                n:1
            },
            //自定义配置
            directives:{
                big(element,bangding){
                    element.innerText = bangding.value*10
                },
                fbind:{
                    //指令与元素成功绑定时(一上来)
                    bind(element,bangding){
                        element.value = bangding.value;
                    },
                    //指令所在元素被插入页面时
                    inserted(element,bangding){
                        element.focus();
                    },
                    //指令所在的模板被重新解析时
                    update(element,bangding) {
                        element.value = bangding.value;
                    },
                }
            }
        })
        const vm2 = new Vue({
            el:"#root2",
            data:{
                x:1,
            }
        })
    </script>
</body>

Vue_浏览器本地存储

<!--
        Window.sessionStorage 和 Window.localStorage统称为WebStorage
            1.浏览器端通过Window.sessionStorage(当浏览器关闭时,里面存储的数据也将跟着清空)和Window.localStorage(当浏览器关闭时,里面存储的数据不会清空,并随着浏览器再次打开时,还是存储在原位)属性来实现本地存储机制
            2.相关API:
                1.sessionStorage / localStorage.setItem('key','value');
                    该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值
                2.sessionStorage / localStorage.getItem('key');
                    该方法接受一个键名作为参数,返回键名对应的值
                3.sessionStorage / localStorage.removeItem('key');
                    该方法接受一个键名作为参数,并把该键名从存储中删除
                4.sessionStorage / localStorage.clear();
                    该方法会清空存储中的所有数据

        备注:
            1.sessionStorage存储的内容会随着浏览器窗口关闭而消失。
            2.localStorage存储的内容,需要手动清除才会消失
            3.sessionStorage / localStorage.getItem('key')如果里面的key对应的value获取不到,那么getItem的返回值时null
            4.JSON.parse(null) 的结果依然是null
    -->     
<body>
    <button οnclick="saveLocal()">点我保存一个数据</button>
    <button οnclick="readLocal()">点我读取一个数据</button>
    <button οnclick="deleteLocal()">点我删除一个数据</button>
    <button οnclick="clearLocal()">点我清空数据</button>
    

    <script type="text/javascript">
        //当浏览器要保存一个对象时
        let p = {name:"黄健聪",age:18}

        function saveLocal(){//setItem是设置保存数据
            localStorage.setItem('msg','hello')
            localStorage.setItem('Person',JSON.stringify(p))//当使用JSON.stringify()时,可把对象转为正常的显示
        }
        function readLocal(){
            //读取打印
            console.log(localStorage.getItem('msg'));
            let result = localStorage.getItem('Person')
            console.log(JSON.parse(result))
        }
        function deleteLocal(){
            localStorage.removeItem('msg')
        }
        function clearLocal(){
            localStorage.clear()
        }
    </script>
</body>

下面使用的是Vue的组件化,后缀名为vue的

Vue_mixin混入配置

<!--
    mixin(混入)
        功能:可以把多个组件共用的配置提取成一个混入对象
        使用方式:
            第一步定义混合,例如
            分别暴露export const mixin={
                data(){...}
                methods:{...}
                ...
            }
            第二步使用混入,例如:
                (1).全局混入:Vue.mixin(混入对象名(mixin))
                (2).局部混入:mixins:['混入对象名(mixin)']
-->

Vue_plugins插件

//如果本组件里面声明了和混入配置一样的data属性,那么本组件data的属性优先级大于混合配置的

export default{
    install(Vue){
       //全局过滤器
       Vue.filter('mySlice',function(value){
            return value.slice(0,4)
       })
       //全局自定义组件
       Vue.directive('fbind',{
        //指令与元素成功绑定时(一上来)
        bind(element,bangding){
            element.value = bangding.value;
        },
        //指令所在元素被插入页面时
        inserted(element,bangding){
            element.focus();
        },
        //指令所在的模板被重新解析时
        update(element,bangding) {
            element.value = bangding.value;
        },
    })
      //全局定义混入
      Vue.mixin({
          data(){
              return{
                  a:100
              }
          }
      })
    }
}

Vue_props配置

<!--
    配置项props
        功能:让组件接收外部传过来的数据
            (1).传递数据:
                <组件名 name="xxx" />
            (2).接收数据:
                第一种方式(只接收):
                    props:['name' '....' ]

                第二种方式(限制类型)
                    props:{
                        name:String,
                        age:Number
                    }

                第三种(限制类型、限制必要性、指定默认值);
                    props:{
                        name:{
                            type:String,类型
                            required:true,必要性
                            default:'老王';默认值,一般与必要性不能一起用
                        }
                    }
                备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会出现警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据
-->

 <Student name="黄健聪" :age="18" sex="男" /><!--age上加上 : 等于获取引号里面的数字从而不是字符串类型-->

Vue_scoped属性

scoped样式
​
  作用:让样式在局部生效,防止冲突
​
  写法:<style scoped></style>
  加上scoped时,那么就算其他组件有共同的class名,也会只服务当前区域的class 

<!--当引入样式时:
  import Student from './components/Student.vue'
  import School from './components/School.vue'//当这里的组件有相同的class样式时,会先应用后面的,因为会覆盖掉前面的并且是后来居上的原理-->

Vuetoolist案例浏览器本地存储

1.当使用JSON.stringify()时,可把对象转为正常的显示 如代码所示: //当浏览器要保存一个对象时 let p = {name:"黄健聪",age:18} function saveLocal(){//setItem是设置保存数据 window.localStorage.setItem('Person',JSON.stringify(p)) //当使用JSON.stringify()时,可把对象转为正常的显示 } 得到:

2.当使用JSON.parse()时,可把对象转为正常的显示

如下图所示:

得到:

Vue自定义组件事件

##组件的自定义事件
    1.一种组件间通信的方式,适用于:子组件===>父组件
    2.使用场景:A是父组件,B是子组件,B想给A传递数据,那么就要在A中给B绑定自定义事件(事件的回调)
    3.绑定自定义事件:
        1.第一种方式,在父组件中:例:<Student @huangjiancong="demo" />或<Student v-on:huangjiancong="demo" />
        2.第二种方式,在父组件中:
            例:<Student ref="student"  />
                回调函数
            demo(name,...params){
            //当子元素传入多个元素给到父元素时,可以用...params来声明一个数组存放
            console.log('app的demo被调用了',name,params)
            this.Studentname=name
            },
            mounted(){
                this.$refs.student.$once('huangjiancong',this.demo)
            }
​
            3.若想让自定义事件只能触发一次,可以使用once--<Student v-on.once:huangjiancong="demo" />
            加上once之后,事件只能触发一次
            或 mounted(){
                this.$refs.student.$once('huangjiancong',this.demo)
            }
        
    4.触发自定义事件:this.$emit('huangjiancong',想传过去的数据)
    5.解绑自定义事件:this.$off('huangjiancong')--只能解绑一个
    6.组件上也可以绑定原生DOM事件,需要使用native修饰符.
    7.注意:通过this.$refs.ref绑定的数据.$on('huangjiancong',上面的回调函数)绑定自定义事件时,回调要么配置在methods(像上面的那个回调函数那样子写),要么用箭头函数,否则this的指向会出问题
​

全局事件总线

## 全局事件总线(GlobalEventBus)--->一种组件间通信的方式,适用于任意组件间通信

1.安装全局事件总线:

(1).在main.js上的

      new Vue({
​
      beforeCreate(){
​
          Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
​
      }
​
   })

2.使用事件总线:

(1).接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组组件自身

   methods(){
    demo(data){

      .....

    }

  }

  mounted(){

    this.$bus.$on('xxx',this.demo) 如果没有用到方法的话,那就得用箭头函数来代替

  }
 ```

(2).提供数据:this.$bus.$emit('xxx',数据)

3.最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件

消息的订阅(subscibe)与发布(publish)

## 1.一种组件间通信的方式,适用于任意组件通信。

2.使用步骤:

1.安装pubsub:npm i pubsub-js

2.引入:import pubsub from 'pubsub-js' 无论是接收的还是传递的都要引入

3.接收数据:A组件想接收数据,则在A组件中订阅消息(即接收数据的),订阅的回调留在A组件自身。

  methods(){
        demo(data){
          .....
        }
      },
      mounted(){
        this.pid = pubsub.subscribe('xxx',this.demo) 订阅消息
         如果不用方法的话,那就直接箭头函数声明
      }

4.提供消息:pubsub.publish('xxx',数据)

5.最好在beforeDestroy中,用pubsub.unsubscribe(this.pid)去取消订阅

$nextTick(function(){})(在增加编辑的Vue里面使用)

## nextTick

1.语法:this.$nextTick(function(){})

2.作用:在下一次DOM更新结束后执行其指定的回调

3.什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在this.$nextTick(function(){})所指定的回调函数中执行

过渡与动画

Vue封装的过渡与动画

1.作用:再插入、更新或移除DOM元素时,在合适的时候给元素添加样式类名。

2.写法:

1.准备好样式:

1.元素进入的样式:

(1).v-enter:进入的起点

(2).v-enter-active:进入过程中

(3).v-enter-to:进入的终点

2.元素离开的样式:

(1).v-leave:离开的起点

(2).v-leave-active:离开的过程中

(3).v-leave-to:离开的终点

3.使用<transition>包裹要过度的元素,并配置name属性:

   ```Vue

<transition> <h1 v-show="isShow">你好啊!</h1> </transition> ```

4.备注:若有多个元素需要过渡,则需要使用:<transition-group> ,且给每个元素都要指定key值

       ```Vue
 <!-- 多个元素过渡 -->

            <transition-group appear>

              <h1 v-show="!isShow" key="1">你好啊</h1>

              <h1 v-show="isShow" key="2">大家好</h1>

            </transition-group>

配置代理方式1and方式2

## 方法二

编写vue.config.js配置具体代理规则:

 //方法二

 devServer: {

  proxy: {

   '/api': { //匹配所有以 '/api1'开头的请求路径

    target: 'http://localhost:5000', //要访问的服务器(获取数据)

    pathRewrite:{'^/api':''},

    ws: true,//用于支持websocket

    changeOrigin: true//用于控制请求头中的host值

   },

   '/demo': {

    target: 'http://localhost:5001', //要访问的服务器(获取数据)

    pathRewrite:{'^/demo':''},

    ws: true,//用于支持websocket

    changeOrigin: true//用于控制请求头中的host值

   }

  }

 }

/*

changeOrigin设置为true时,服务器收到的请求头中的host为:(要拿数据服务器的端口)localhost:5000

changeOrigin设置为false时,服务器收到的请求头中的host为:(本机端口)localhost:8080

changeOrigin默认为true

*/

插槽

## 插槽

1.作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件===>子组件

2.分类:默认插槽、具名插槽、作用域插槽

3.使用方式:

1.默认插槽:

父组件中:

            <category>

                   <div>html结构1</div>

            </catgory>

子组件中:

  <template>
        <div class="category">
          <!--定义插槽-->
          <slot>插槽默认内容....</slot>
        </div>
   </template>

2.具名插槽:

父组件:

 <category title="游戏">
            <ul slot="center">
              <li v-for="(item,index) in games" :key="index">
                {{item}}
              </li>
            </ul>
            <div slot="footer">
              <a href="#">单机游戏</a>
              <a href="#">网络游戏</a>
            </div>
 </category> 

子组件:

   <template>
         <div class="category">
          <h3>{{title}}</h3>
            <!--定义插槽-->
            <slot name="center"></slot>
            <slot name="footer"></slot>
          </div>
    </template>

3.作用域插槽:

1.理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者决定。(games数据在category组件中,但使用数据所遍历出来的结构由App组件决定)

  <template>
        <div class="container">
      <category title="Beyond">
      <!--要想接收子组件传来的数据,一定要用到template   无序列表-->
      <template scope={games}>
      <ol>
        <li v-for="(item,index) in games" :key="index">
          {{item}}
        </li>
        </ol>
      </template>
      </category>
      <!--有序列表-->
      <category title="游戏">
      <template scope={games}>
        <ul>
        <li v-for="(item,index) in games" :key="index">
          {{item}}
        </li>
        </ul>
          <a href="#">单机游戏</a>
          <a href="#">网络游戏</a>
      </template>
      </category>
     <!--生成h4标签-->
      <category title="视频">
      <template scope={games}>
        <h3 v-for="(item,index) in games" :key="index">
          {{item}}
        </h3>
      </template>
      </category>
    </div>
    </template>

子组件中:

     <script>
      export default {
        name:"category",
        props:['title'],
        data() {
          return {
          music:['光辉岁月','不再犹豫','海阔天空','情人'],
      games:['Gta5','荒野大嫖客','QQ飞车','CF'],

      films:['哈利波特','精灵旅社','新灰姑娘','密室逃亡']
      }
  },
  }
    </script>

Vuex

## 搭建vuex环境

1.创建文件:src/store/index.js

//该文件用于创建Vuex中最为核心的store

//先下载插件 npm i vuex@3 ---备注下载vuex3 如果没有@3的话就默认下载vuex4,vue2下载vuex4会报错 (vue2搭配vuex3,vue3搭配vuex4)

 //1.引入Vuex
  import Vue from 'vue'
  import Vuex from 'vuex'
  Vue.use(Vuex)
  //准备actions——用于响应组件中的动作
  const actions = {},
  //准备mutations——用于操作数据(state)
  const mutations = {},
  //准备state——用于存储数据
  const state = {
 }
  //创建并暴露(导出)store
  export default new Vuex.Store({
    actions,
    mutations,
    state,

  })

2.在main.js中创建vm时传入store配置项

	import Vue from 'vue'
    import App from './App.vue'
    import store from './store/index'
    Vue.config.productionTip = false
    new Vue({
    el:"#app",
    store,
    render: h => h(App),
  })

2.基本使用

1.初始化数据、配置actions、配置mutations、操作文件store.js

 //该文件用于创建Vuex中最为核心的store
 //先下载插件 npm i vuex@3 ---备注下载vuex3 如果没有@3的话就默认下载vuex4,vue2下载vuex4会报错 (vue2搭配vuex3,vue3搭配vuex4)
  //1.引入Vuex
  import Vue from 'vue'
  import Vuex from 'vuex'
  Vue.use(Vuex)
  //准备actions——用于响应组件中的动作
  const actions = {
    addActions(context,value){
      context.commit('addmutations',value)
    },
    subActions(context,value){
      context.commit('submutations',value)
    },
    jiaddActions(context,value){
      if(context.state.sum%2){
        context.commit('addmutations',value)
      }
    },
    addWaitActions(context,value){
      setTimeout(()=>{
        context.commit('addmutations',value)
      },2000)
    }
  }
 //准备mutations——用于操作数据(state)
 const mutations = {
    addmutations(state,value){
      state.sum += value
    },
    submutations(state,value){
      state.sum -= value
    },
  }
  //准备state——用于存储数据
  const state = {
    sum:0

  }
  //创建并暴露(导出)store
 export default new Vuex.Store({
    actions,
    mutations,
    state,
  })

2.组件中读取vuex中的数据:$store.state.sum

3.组件中修改vuex中的数据:$store.dispatch('action中的方法名',数据)或$store.commit('mutations中的方法名',数据)

备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,既不写dispatch,直接编写commit

getters的使用

4.getters的使用

1.概念:当state中的数据需要经过加工后再使用时,可以使用getters加工

2.在store.js中追加getters配置

  ......
  const getters = {
    bigSum(state){
     return state.sum*10
    }
  }
  //创建并暴露(导出)store
  export default new Vuex.Store({
    actions,
    mutations,
    state,
    getters
  })

3.组件中读取数据:$store.getters.bigSum(getters里面定义的函数)

四个map方法的使用

## 四个map方法的使用

1.mapState方法:用于帮助我们映射state中的数据为计算属性

computed:{
      //借助mapState生成计算属性,从state中读取数据。(对象写法) key值可以跟value值名字不一样
      //...mapState({sum:'sum',school:'school',subject:'subject'})
      //借助mapState生成计算属性,从state中读取数据。(数组写法) key值可以跟value值名字要一样实则对应上面的sum:'sum'
      ...mapState(['sum','school','subject']),
      }

2.mapGetters方法:用于帮助我们映射getters中的数据为计算属性

computed:{
      //借助mapGetters生成计算属性,从state中读取数据。(对象写法) key值可以跟value值名字不一样
      //...mapGetters({bigSum:'bigSum'})
      //借助mapGetters生成计算属性,从state中读取数据。(数组写法) key值可以跟value值名字要一样,实则对应上面的bigSum:'bigSum'
      ...mapGetters(['bigSum'])
    }

模块化+命名空间

1.目的:让代码更好维护,让多种数据分类更加明确。

2.修改store.js

const countAbout = {
    namespaced = true,//开启命名空间
    state:{x:1},
    mutations:{...}
    actions:{...}
    getters:{
        bigSum(state){
            return state.sum*10
        }
    }
}
const personAbout = {
    namespaced = true,//开启命名空间
    state:{x:1},
    mutations:{...}
    actions:{...}
    getters:{
        bigSum(state){
            return state.sum*10
        }
    }
}
const store = new Vuex.Store({
    modules:{
        countAbout,
        personAbout
    }
})

3.开启命名空间后,组件中读取state数据:

//方式一,自己直接读取
this.$store.state.personAbout.list
//方式二,借助mapState读取:
...mapState('countAbout',['sum','school','subject']),

4.开启命名空间后,组件中读取getters数据:

...mapState('countAbout',['sum','school','subject']),

封装axios进行api的调用

1.先创建一个名为api的文件夹  axios,vuex

    1.先进行下载关键的插件 npm i axios       npm i vuex@3(vue2下载版本3的vuex,否则会出现版         本过高的报错).

     2.在api的文件夹里面创建一个封装axios的文件(request.vue),文件内容如下:

//对于axios进行二次封装
import axios from 'axios';

//引入进度条  start:表示进度条的开始 ,done表示进度条的结束
import nprogress from 'nprogress';

//引入进度条的样式
import 'nprogress/nprogress.css'

//1.利用axios对象方法create,去创建一个axios实例
//2.requests就是axios,只不过稍微配置一下
const requests = axios.create({
    //配置对象
    //基础路径,发送请求的时候,路径当中会出现api 
    baseURL:'/api',
    //代表请求超时的时间5s
    timeout:5000
});
//请求拦截器:在发送请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use((config)=>{
    nprogress.start()
    //config:配置对象,对象里面有一个属性很重要,headers请求头
    return config 
})
//响应拦截器
requests.interceptors.response.use((res)=>{
    nprogress.done()
    //成功的回调函数,服务器相应的数据回来之后,响应拦截器可以检测到,可以做一些事情
    return res.data
},(error)=>{
    //响应失败的回调函数
    return Promise.reject(new Error('faile'))
})


//向外暴露
export default requests

     3.继续在api的文件夹里面创建一个统一管理api的文件,代码如下:

//这个文件是来建立统一API管理
import requests from "./request";
import mockRequest from './mockRequest'

//三级联动的接口
// /api/product/getBaseCategoryList  get请求 无参数
   
//发送请求:axios发请求返回结果Promise对象
export const reqCategoryList = ()=>{
    return requests({
        url:'product/getBaseCategoryList', 
        method:'GET'
    })
}

        

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值