Vue学习

学习链接:https://www.bilibili.com/video/BV15741177Eh
学习课件:https://github.com/CodeZBW/vueCourse_PPT
知识点整理(来自网友):https://nanzx.top/categories/Vue/
1. Vue中的MVVM模型。
Vue中的MVVM模型指的是:Model、View、ViewModel。
2. v-bind动态绑定class:https://blog.csdn.net/qq_43077894/article/details/83544399
3. ES6对象字面量的增强写法。
  1. 属性的增强写法:
const name = 'jack';
const age = 18;
const height = 1.88;

//ES6的语法:
const obj = {
	name,
	age,
	height
}

//ES5的语法:
//const obj = {
//	name: name,
//	age: age,
//	height: height
//}
  1. 函数的增强写法:
//ES6的语法:
const obj = {
	run() {
	}
}


//ES5的语法:
//const obj = {
//	run: function() {
//	}
//}

4. const定义的基本类型不能改变,但是定义的对象是可以通过修改对象属性等方法来改变的。
const obj = {
	name: 'jack'
}
obj.name = 'lily';
console.log(obj); //lily
5. v-on参数。

当通过methods中定义方法,以供@click调用时,需要注意参数问题:

<div id = "app">
	<h2>点击次数:{{counter}}</h2>
	<button @click="add">+1</button>
	<button @click="addten">+10</button>
</div>
methods: {
	add(event) {
		console.log(event);
		this.counter++;
	}
	addten(count, event) {
		console.log(event);
		this.counter += 10;
	}
}
  1. 情况一:如果该方法不需要额外参数,那么方法后的()可添加可不添加。
  2. 情况二:如果该方法需要额外参数,如果调用方法的时候写了()但没有传入参数,那么函数的形参为undefined。如果没写(),那么vue会默认将浏览器生成的event事件对象作为参数传入到方法中。
  3. 情况二:如果需要同时传入某个参数,同时需要event时,可以通过$event传入事件。注意:<button @click=“addten(abc, $event)”>+10中,abc作为变量传递,abc的值绑定在data里。
6. v-on的修饰符。
<button @click.stop='btnClick'>按钮</button>
<form action=''>
	<input type='submit' value='提交' @click.prevent='submitClick'>
</form>
<input type='text' @keyup.enter='keyup'> <!--按下enter按键才会执行btnClick方法-->
<button @click.once='btn2Click'>按钮2</button>

(1) .stop - 调用events.stopPropagation()。禁止冒泡事件。
(2) .prevent - 调用event.preventDefault()。禁止默认事件,eg:表单自动提交。
(3) .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
(4) .native - 监听组件根元素的原生事件。
(5) .once - 只触发一次回调。

7. 登录方式切换的input复用问题。

        若设置了“使用账号密码登录”和“使用邮箱登录”两种方式时,当用户在“使用账号密码登录”方式下输入一些数据,临时改变主意想使用邮箱登录,此时由于input复用问题,当用户切换登录方式的时候,input里会保留用户原来输入的数据,如果想要实现“用户切换登录方式时清空input的数据(也就是不复用input)”,给每一个input设置不同的key即可。

8. v-show和v-if的区别。
  1. v-if:当条件为false时,包含v-if指令的元素,根本就不会存在dom中。
  2. v-show:当条件为false时,v-show只是给我们的元素添加一个行内元素:display:none。
  3. 当切换频率比较高的时候,建议使用v-show,因为v-show不会把dom删除掉,性能较好。当只有一次切换时,通常使用v-if。
9. v-for遍历数组和对象。
  1. 遍历数组:
<ul>
	<li v-for='item in arr'>{{item}}</li> <!--输出数组的值-->
	<li v-for='(item, index) in arr'>{{index + 1}}-{{item}}</li><!--输出数组的索引和值-->
</ul>
  1. 遍历对象:
<ul>
	<li v-for='item in obj'>{{item}}</li> <!--输出对象的值-->
	<li v-for='(value, key) in obj'>{{value}}-{{key}}</li><!--输出对象的value和key-->
	<li v-for='(value, key, index) in obj'>{{value}}-{{key}}-{{index}}</li><!--输出对象的value、key和index-->
</ul>
10. 有些数组操作不是响应式的。

    通过索引值修改数组的元素。

this.arr[0] = 'hello';
//此时数组内容已经改变了,但页面上无法显示出来。
11. 修改数组的特殊方法——Vue.set()。
//set(要修改的对象,索引值,修改后的值)
Vue.set(this.arr, 0, 'hello');
12. JS的高阶函数。
  1. filter函数。

        filter函数中的回调函数必须返回一个Boolean值,当返回true时,函数内部会自动将这次回调的item加入到新的数组中;当返回false时,函数内部会过滤掉这次的item。

const arr = [10, 20, 111, 222, 444, 40, 50];
let newArr = arr.filter(function(item) {
	return item < 50;
});
//newArr = [10, 20 ,40]
  1. map函数。
const arr = [10, 20, 40, 50];
let newArr = arr.map(function(item) {
	return item * 2;
});
//newArr = [20, 40, 80, 100]
  1. reduce函数。

        reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T) : T;
        reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T) : T;
reduce(回调函数:(上一个值,当前值,当前索引){},初始值)

const arr = [20, 40, 80, 100];
let total = arr.reduce(function(preValue, currentValue) {
	return preValue + currentValue;
}, 0);
//total = 240
//第一次:preValue:0,currentValue:20;
//第二次:preValue:20,currentValue:40;
//第三次:preValue:60,currentValue:80;
//第四次:preValue:140,currentValue:100;
//最终返回结果:240
  1. 三个函数综合使用。
const arr = [10, 20, 111, 222, 444, 40, 50];
let total = arr.filter(i => i < 100).map(i => i * 2).reduce((pre, cur) => pre + cur);
//total = 240
13. 响应式绑定和双向绑定。

响应式绑定:data改变,页面显示也会随之改变。
双向绑定:data改变,页面显示也会随之改变;用户修改页面上的值,data也会随之改变。eg:页面上用户输入input的value值,data会随之改变。v-model就是这样实现表单的双向绑定。

14. v-model的修饰符。
<input type='text' v-model.lazy='msg'> <!--按下enter按键或者输入框失去焦点时才会触发双向绑定-->
<h2>{{msg}}</h2>
  1. lazy修饰符:

默认情况下,v-model默认是在input事件中同步输入框的数据的。也就是说,一旦有数据发生改变,对应的data中的数据就会自动发生改变。
lazy修饰符可以让数据在失去焦点或者回车时才会更新。

  1. number修饰符:

默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理,但是如果我们希望处理的是数字类型,那么最好直接将内容当做数字处理。
number修饰符可以让在输入框中输入的内容自动转成数字类型。

  1. trim修饰符:

如果输入的内容首尾有很多空格,通常我们希望将其去除。
trim修饰符可以过滤内容左右两边的空格。

15. 注册组件的基本步骤。
  1. 调用Vue.extend()方法创建组件构造器。
  2. 调用Vue.component()方法注册组件。
  3. 在Vue实例的作用范围内使用组件。
<div id='app'>
	<!--3.使用组件-->
	<my-cpn></my-cpn>
</div>
<script>
	//1.创建组件构造器
	const myComponent = Vue.extend({
		template: `
			<div>
				<h2>组件标题</h2>
				<p>我是组件中的一个段落内容</p>
			</div>`
		});
	//2.注册组件,并且定义组件标签的名称
	Vue.component('my-cpn', myComponent);
	
	const app = new Vue({
		el: '#app',
	});
</script>
16. 全局组件和局部组件。
  1. 全局组件:可以在多个Vue实例下使用。
<!--my-cpn做为全局组件既可以在app实例下使用,又可以在app1实例下使用-->
<div id='app'>
	<my-cpn></my-cpn>
</div>
<div id='app1'>
	<my-cpn></my-cpn>
</div>
<script>
	const myComponent = Vue.extend({
		template: `
			<div>
				<h2>组件标题</h2>
				<p>我是组件中的一个段落内容</p>
			</div>`
		});
	Vue.component('my-cpn', myComponent);
	
	const app = new Vue({
		el: '#app',
	});
	const app1 = new Vue({
		el: '#app1',
	});
</script>
  1. 局部组件:只能在当前Vue实例下使用。
<!--my-cpn作为局部组件只能在app实例下使用-->
<div id='app'>
	<my-cpn></my-cpn>
</div>
<script>
	const myComponent = Vue.extend({
		template: `
			<div>
				<h2>组件标题</h2>
				<p>我是组件中的一个段落内容</p>
			</div>`
		});
	const app = new Vue({
		el: '#app',
		components: {
			my-cpn: myComponent
		}
	});
</script>
17. 父组件和子组件。
<div id='app'>
	<my-cpn></my-cpn>
</div>
<script>
	//1.创建第一个组件构造器(子组件)
	const cpnC1= Vue.extend({
		template: `
			<div>
				<h2>组件标题1</h2>
				<p>我是组件中的一个段落内容</p>
			</div>`
		});
	//2.创建第二个组件构造器(父组件)
	const cpnC2= Vue.extend({
		template: `
			<div>
				<h2>组件标题2</h2>
				<p>我是组件中的一个段落内容</p>
			</div>`
		components: {
			cpn1: cpnC1
		}
	});
	//root组件
	const app = new Vue({
		el: '#app',
		components: {
			my-cpn: cpnC2
		}
	});
</script>
18. 注册组件的语法糖写法。
  1. 全局组件
<!--全局组件-->
<div id='app'>
	<my-cpn></my-cpn>
</div>
<script>
	Vue.component('my-cpn', {
		template: `
			<div>
				<h2>组件标题</h2>
				<p>我是组件中的一个段落内容</p>
			</div>`
	});	
	const app = new Vue({
		el: '#app',
	});
</script>
  1. 局部组件
<!--局部组件-->
<div id='app'>
	<my-cpn></my-cpn>
</div>
<script>
	const app = new Vue({
		el: '#app',
		components: {
			'my-cpn': {
				template: `
					<div>
						<h2>组件标题</h2>
						<p>我是组件中的一个段落内容</p>
					</div>`
			}
		}
	});
</script>
19. 组件模板的抽离写法。
  1. 使用script标签
<div id='app'>
	<cpn></cpn>
</div>
<!--1.script标签,注意:类型必须是text/x-template-->
<script type='text/x-template' id='cpn'>
	<div>
		<h2>组件标题</h2>
		<p>我是组件中的一个段落内容</p>
	</div>
</script>

<script>
	Vue.component('cpn', {
		template: '#cpn'
	});	
	const app = new Vue({
		el: '#app',
	});
</script>
  1. 使用template标签。
<div id='app'>
	<cpn></cpn>
</div>
<!--2.template标签-->
<template id='cpn'>
	<div>
		<h2>组件标题</h2>
		<p>我是组件中的一个段落内容</p>
	</div>
</template>

<script>
	Vue.component('cpn', {
		template: '#cpn'
	});	
	const app = new Vue({
		el: '#app',
	});
</script>
20. 组件中的data。

        组件对象也有一个data属性(还可以有methods等属性),但这个data属性必须是一个函数,而且这个函数返回一个对象,对象内部保存着数据。
        组件中的data为什么是一个函数?
        当多次调用同一个组件时,多个组件共有同一个data对象,如果data不是一个函数,只是一个普通的对象,那么会造成下一个组件修改上一个组件的data值的问题。

<div id='app'>
	<cpn></cpn>
</div>
<template id='cpn'>
	<div>
		<h2>{{title}}</h2>
		<p>我是组件中的一个段落内容</p>
	</div>
</template>

<script>
	Vue.component('cpn', {
		template: '#cpn',
		data() {
			return {
				title: 'abc'
			}
		}
	});	
	const app = new Vue({
		el: '#app',
	});
</script>
21. 父子组件之间的通信。
  1. 父传子:props。
  2. 子传父:自定义事件。
    在这里插入图片描述
22. 父子组件通信:父传子(props)。
<div id='app'>
  <cpn :cmovies='movies' :cmessage='message'></cpn>
</div>
<template id='cpn'>
  <div>
    <h2>{{ cmessage }}</h2>
    <p>{{ cmovies }}</p>
  </div>
</template>

<script>
  const cpn = {
    template: "#cpn",
    props: ["cmovies", "cmessage"],
    //也可以写成对象:
    //props: {
    //	cmovies: {
    //		type: Array,
    //		defalut() {
    //			return [];	//当类型为对象或者数组时,默认值必须是一个函数
    //		}
    //	},
    //	cmessage: {
    //		type: String,	//类型限制
    //		default: 'initValue',	//初始默认值
    //		required: true	//必须填写
    //	}
    //}
    data() {
      return {};
    },
  };
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello",
      movies: ["海王", "海尔兄弟", "海贼王"],
    },
    components: {
      cpn,
    },
  });
</script>
23. props驼峰标识。

当props里的变量名使用了驼峰命名,但在v-bind里是不支持驼峰的,需要做以下转换。

<div id='app'>
  <cpn :c-info='info'></cpn>
</div>
<template id='cpn'>
  <p>{{ cInfo }}</p>
</template>

<script>
  const cpn = {
    template: "#cpn",
    props: {
      cInfo: {
        type: Object,
        defalut() {
          return {};
        },
      },
    },
    data() {
      return {};
    },
  };
  const app = new Vue({
    el: "#app",
    data: {
      info: {
        name: "why",
        age: 18,
        height: 1.88,
      },
    },
    components: {
      cpn,
    },
  });
</script>
24. 父子组件通信:子传父。
  1. 在子组件中,通过$emit()来触发事件。
  2. 在父组件中,通过v-on来监听子组件事件。
<!-- 父组件模板 -->
<div id='app'>
  <cpn @itemclick='cpnClick'></cpn>
</div>
<!-- 子组件模板 -->
<template id='cpn'>
  <div>
    <button v-for='item in categories' 
    		@click='btnClick(item)'>
    		{{ item.name }}
    </button>
  </div>
</template>

<script>

  // 1.子组件
  const cpn = {
    template: "#cpn",
    data() {
      return {
        categories: [
          { id: 'aaa', name: '热门推荐' },
          { id: 'bbb', name: '手机数码' },
          { id: 'ccc', name: '家用家电' },
          { id: 'ddd', name: '电脑办公' },
        ]
      }
    },
    methods: {
      btnClick(item) {
        this.$emit('itemclick', item);
      }
    },
  };
  // 2.父组件
  const app = new Vue({
    el: "#app",
    data: {
      info: {
        name: "why",
        age: 18,
        height: 1.88,
      },
    },
    components: {
      cpn,
    },
    methods: {
      cpnClick(item) {
        console.log(item)
      }
    }
  });
</script>
25. 父子组件的访问方式。
  1. 父组件访问子组件:使用$children或$refs。想要拿到所有子组件使用$children,想要拿到某个指定的子组件使用$refs。
<!-- 父组件模板 -->
<div id='app'>
  <cpn></cpn>
  <cpn></cpn>
  <cpn ref="aaa"></cpn>
  <button @click='btnClick'>按钮</button>
</div>
<!-- 子组件模板 -->
<template id='cpn'>
  <div>
    我是子组件
  </div>
</template>

<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello"
    },
    components: {
      cpn: {
        template: '#cpn',
        methods: {
          showMessage() {
            console.log('showMessage')
          }
        },
      }
    },
    methods: {
      btnClick() {
        //1.$children
        console.log(this.$children);
        //2.$refs
        console.log(this.$refs.aaa);
      }
    }
  });
</script>
  1. 子组件访问父组件:使用$parent。
<!-- 父组件模板 -->
<div id='app'>
  <cpn></cpn>
</div>
<!-- 子组件模板 -->
<template id='cpn'>
  <div>
    <h2>我是cpn组件</h2>
    <ccpn></ccpn>
  </div>
</template>
<template id='ccpn'>
  <div>
    <h2>我是子组件</h2>
    <button @click='btnClick'>按钮</button>
  </div>
</template>

<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello"
    },
    components: {
      cpn: {
        template: '#cpn',
        data() {
          return {
            name: '我是cpn组件的name'
          }
        },
        components: {
          ccpn: {
            template: '#ccpn',
            methods: {
              btnClick() {
                //1.访问父组件$parent
                console.log(this.$parent);
                console.log(this.$parent.name);
                //2.访问root组件$root
                console.log(this.$root);
                console.log(this.$root.message);
              }
            },
          }
        }
      }
    }
  });
</script>
26. slot-插槽的基本使用。
  1. 在模板里设置slot标签,作为预留位置使用。
  2. 使用组件时填充slot内容。
  3. 在slot标签中可设置默认内容,若使用组件时不填充slot内容,则以默认内容填充,若填充了slot内容,则替换掉默认内容。
<div id='app'>
  <cpn>
    <!-- 2. 使用组件时填充slot内容。 -->
    <button>button</button>
  </cpn>
  <cpn></cpn>
  <cpn></cpn>
</div>
<template id='cpn'>
  <div>
    <h2>我是cpn组件</h2>
    <!-- 1. 在模板里设置slot标签,作为预留位置使用。 -->
    <slot></slot>
    <!-- 3. 设置默认内容,若使用组件时不填充slot内容,则以默认内容填充。 -->
    <!-- <slot><p>我是默认内容</p></slot> -->
  </div>
</template>

<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello"
    },
    components: {
      cpn: {
        template: '#cpn',
        data() {
          return {}
        },
      }
    }
  });
</script>
27. slot-具名插槽的使用。
  1. 当模板里有多个slot标签时,给模板里的每个slot标签设置name属性。
  2. 使用组件时,当要用自定义标签替代默认标签时,在自定义标签中设置slot属性为slot标签中name属性的值,这样即可替代指定slot标签的默认内容。
<div id='app'>
  <cpn>
  	<template v-slot:left>
  		<button>title</button>
  	</template>
  </cpn>
</div>
<template id='cpn'>
  <div>
    <h2>我是cpn组件</h2>
    <slot name='left'><span>left</span></slot>
    <slot name='center'><span>center</span></slot>
    <slot name='right'><span>right</span></slot>
  </div>
</template>

<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello"
    },
    components: {
      cpn: {
        template: '#cpn',
        data() {
          return {}
        },
      }
    }
  });
</script>
28. 变量作用域。
<div id='app'>
  <!-- 此处的isShow的值为true -->
  <cpn v-show='isShow'></cpn>
</div>
<template id='cpn'>
  <div>
    <h2>我是cpn组件</h2>
    <!-- 此处的isShow的值为false -->
    <h2 v-show='isShow'>我是cpn组件的内容</h2>
  </div>
</template>

<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello",
      isShow: true
    },
    components: {
      cpn: {
        template: '#cpn',
        data() {
          return {
            isShow: false
          }
        },
      }
    }
  });
</script>
29. 作用域插槽的使用。
  1. 父组件替换插槽的标签,但是内容由子组件来提供。
<div id='app'>
  <cpn>
    <!-- 当父组件想要拿到子组件的数据来替换slot标签的内容,需要设置v-slot:default="slotProps",通过slotProps.xxx获取子组件的数据 -->
    <template v-slot:default="slotProps">
      <span v-for='item in slotProps.data'>{{item}} * </span>
    </template>
  </cpn>
</div>
<template id='cpn'>
  <div>
    <!-- 可以是任意命名,并不一定是为data,也可以写成:abc='pLanguages' -->
    <slot :data='pLanguages'>
      <ul>
        <li v-for='item in pLanguages'>{{item}}</li>
      </ul>
    </slot>
  </div>
</template>

<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello",
    },
    components: {
      cpn: {
        template: '#cpn',
        data() {
          return {
            pLanguages: ['javascipt', 'c++', 'java', 'c#', 'python', 'go', 'swift']
          }
        },
      }
    }
  });
</script>
30. 为什么需要模块化?
  1. 变量名冲突的问题:
            当多人开发时,小明新建了xm1.js文件和xm2.js文件,小红新建了xh1.js文件和xh2.js文件。小明在xm1.js文件中创建了num变量和func函数,而小红在xh.js文件中也创建了num变量和func函数,当小明在xm2.js文件中修改num变量时,同时会修改小红定义的num变量。
            解决方法:闭包。小明和小红在各自的xm1.js和xh1.js中通过在闭包函数中处理业务逻辑,由于在函数内部的变量和函数都有自己的作用域,这样小明和小红花就无法修改别人的变量和函数,就可以解决变量名冲突的问题了。
  2. 代码不可复用:
            当使用闭包解决变量名冲突的问题后,随着而来的是小明在xm1.js中定义的num变量和func函数在xm2.js中无法使用,代码不可复用。
            解决方法:在闭包函数中使用对象类型obj保存num变量和func函数,闭包函数返回obj,将闭包函数复制给一个变量moduleXM,这样小明就可以在xm2.js中通过moduleXM.obj访问xm1.js中的num变量和func函数了。
  3. 常见的模块化规范:
            CommonJS(node使用)、AMD、CMD、ES6的Modules。
31. CommonJS。
  1. 模块化有两个核心:导出和导入。
  2. CommonJS的导出:
module.exports = {
  flag: true,
  test(a, b) {
    return a + b;
  }
}
  1. CommonJS的导入:
  let {flag, test} = require('moduleXM');

  // 等同于
  let _mA = require('moduleXM');
  let flag = _mA.flag;
  let test = _mA.test;
32. ES6的Modules。
  1. import导入:
import { xxx, xxx } from './test.js' //xxx可以是变量名,函数名,类名....

// 统一全部导入
import * as obj from './test.js'
console.log(obj.xxx1);
console.log(obj.xxx2);
console.log(obj.xxx3);
  1. export导出变量:
export let name = 'jack';
export let age = 18;

// 或者这样写
let name = 'jack';
let age = 18;

export { name, age }
  1. export导出函数或类:
export function mul(num1, num2) {
  return num1 + num2;
}

// 或者这样写
function mul(num1, num2) {
  return num1 + num2;
}
export { mul }
  1. 某些情况下,一个模块中包含某个的功能,我们并不希望给这个功能命名,而且让导入者可以自己来命名。这个时候使用export default。注意:同一个模块不能包含多个export default。
export default function(argu) {
  console.log(argu);
}
// 只有使用了export default导出的值才能用import myfunc from './test.js',
// 如果不是使用export default导出的值需要加大括号,即import {myfunc} from './test.js'
import myfunc from './test.js'
myfunc(1);
33. Webpack。

Webpack详解:https://nanzx.top/posts/a5d2/
在这里插入图片描述

34. Vue-CLI相关。

Vue-CLI相关:https://nanzx.top/posts/a9f7/

35. npm run build。

在这里插入图片描述

36. npm run dev。

在这里插入图片描述

37. ES6箭头函数this的指向。
  const obj = {
    aaa() {
      setTimeout(function () {

        // 匿名函数的this指向window
        console.log(this); //window

        setTimeout(function () {
          console.log(this);  //window
        })

        setTimeout(() => {
          console.log(this);
        })
      });

      setTimeout(() => {
        
        // 箭头函数中的this引用的是最近作用域的this
        console.log(this);  //obj对象

        setTimeout(function () {
          console.log(this);  //window
        })

        setTimeout(() => {
          console.log(this);  //obj对象
        })
      });
    }
  }
38. Vue-router详解。

Vue-router详解:https://nanzx.top/posts/426d/

39. Vuex详解。

Vuex详解:https://nanzx.top/posts/19dc/
在这里插入图片描述

40. axios框架的使用——网络请求。

网络请求框架(axios):https://nanzx.top/posts/a86d/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值