赞
踩
渐进式:Vue可以自底向上逐层的应用;
简单应用:只需要一个轻量小巧的核心库;
复杂应用:可以引入各式各样的Vue插件;
1、采用组件化模式,提高复用率,更利于维护;
2、声明式编码,让编码人员无需直接操作DOM,提高效率;
安装上对应vue的扩展,在导入vue.js后,阻止弹出一个安装版本提示。
- <script>
- Vue.config.productionTip = false;
- </script>
Vue小案例——hello
小结:1、想让Vue工作,必须创建一个Vue实例,且要传入一个配置对象;
2、root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法;
3、root容器里的代码被称为:VUE模板(vue模板只能使用实例化的vue对象中的数据);
4、Vue实例和容器是一一对应的;
5、真是开发中只有一个Vue实例,并且会配合组件一起使用;
6、{{***}}中的参数要写js表达式,且参数可以自动读取到data中所有属性;
7、一旦data中的数据发生改变,则模板中的用刀该数据的地方会自动更新;
容器里边可以使用实例之外的参数属性,但是可以使用表达式;
1、表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方;
例如:a、a+b、demo(1)、x===y?'a':'b'
2、js语句
实例:1、if(){}
2、for(){}
(注意:区分js表达式和js代码)
- <body>
- <div id = "root">
- <h1>Hello,{{name}}<h1>
- </div>
-
- <script type = "text/javascript">
- Vue.config.productionTip = false; //阻止Vue在启动后产生提示;
- new Vue({
- el:'#root'; //指定当前Vue实例为哪个容器服务,值通常为css选择器字符串;
- data:{
- name:"尚硅谷"; //data中用于存储数据,数据el所指定的容器去使用
- }
- })
- </script>
- </body>
一个容器里边只能对应一个实例的参数:一对一关系;
- <body>
- <div id = "root1">
- <h1>hello,{{name}},{{address}}</h1>
- </div>
- <div id = "root2">
- <h1>hello,{{name}},{{address}}</h1>
- </div>
- <script type = 'text/javascript'>
- Vue.config.productionTip = false;
- new Vue({
- el:'#root1',
- data:{
- name:'姓名',
- address:'地址';
- }
- })
- new Vue({
- el:'#root2';
- data:{
- name:'尚硅谷',
- address:'地址';
- }
- })
- </script>
- </body>
v-bind:"v-"(Vue的特有的指令方式),为绑定的意思,这个指定可以简化为:" : "
小结:
1、差值语法:
功能:用于解析标签体内容;
写法:{{***}}是js表达式,且可以直接读取到data中的所有属性;
2、指令语法:
功能:用于解析标签(包括:标签属性、标签内容、绑定事件...),
举例:v-bind:href='***'或简写为 :href='***' ,***同样要写js表达式,且可以直接读取到data中的所有属性。
备注:Vue中很多指定,形式都是以:v-???,
- <body>
- <div id = "root">
- <h1>差值语法</h1>
- <h3>你好,{{name}}</h3> //读取是jack
- <hr/>
- <h1>指令语法</h1>
- <a v-bind:href="school.url.toUpperCase()">学习vue框架,名字{{school.name}}</a> //输出的是“尚硅谷”
- </div>
- </body>
- <script>
- Vue.config.productionTip = false; //阻止vue启动时弹出的生产提示
- new Vue({
- el:'#root',
- data:{
- name:'jack',
- school:{
- name:'尚硅谷',
- url:'http://www.baidu.com',
- }
- }
- })
- </script>
执行结果是:
Vue中有2种数据绑定方式:
1、单向绑定(v-bind):数据只能从data流向页面;
2、双向绑定(v-model):数据不仅可以从data流向页面,还可以从页面流向data;
备注:
(1)双向绑定一般都应用在表单元素上(如:input,select等);
(2)v-model:value 可以简写为v-model,因此v-model默认收集的就是value值;
- <body>
- <div id="root">
- 单向数据绑定:<input type = 'text' v-bind:value='name'><br/>
- 双向数据绑定:<input type = 'text' v-model:value='name'><br/>
- </div>
- </body>
- <script type='text/javascript'>
- Vue.config.productionTip=false;
- new Vue({
- el:'#root',
- data:{
- name:'尚硅谷'
- }
- })
- </script>
简写:
- <body>
- <div id="root">
- 单向数据绑定:<input type = 'text' :value='name'><br/>
- 双向数据绑定:<input type = 'text' v-model='name'><br/>
- </div>
- </body>
一、el的两种写法:
(1)、el:"#root";
(2)、v.$mount("#root");
- <body>
- <div id="root">
- 单向数据绑定:<input type = 'text' v-bind:value='name'><br/>
- 双向数据绑定:<input type = 'text' v-model:value='name'><br/>
- </div>
- </body>
- <script type='text/javascript'>
- Vue.config.productionTip=false;
- const v = new Vue({
- // el:'#root',第一种写法
- data:{
- name:'尚硅谷'
- }
- })
- ocnsole.log(v);
- v.$mount("#root"); //第二种写法
- </script>
二、data的两种写法
data的第一种写法:对象式
- <body>
- <div id="root">
- 单向数据绑定:<input type = 'text' v-bind:value='name'><br/>
- 双向数据绑定:<input type = 'text' v-model:value='name'><br/>
- </div>
- </body>
- <script type='text/javascript'>
- Vue.config.productionTip=false;
- new Vue({
- el:'#root',
- data:{
- name:'尚硅谷',
- age:'20'
- }
- })
- </script>
第二种写法:函数式
console.log(this);指向的是Vue对象;
- <body>
- <div id="root">
- 单向数据绑定:<input type = 'text' v-bind:value='name'><br/>
- 双向数据绑定:<input type = 'text' v-model:value='name'><br/>
- </div>
- </body>
- <script type='text/javascript'>
- Vue.config.productionTip=false;
- new Vue({
- el:'#root',
- data:function(){
- return{
- name:'尚硅谷',
- age:'20'
- }
- }
- })
- </script>
小结:
el有两种写法:
1、new Vue时候配置el属性。(1)、el:"#root";
2、先创建Vue实例,随后再通过"实例".$mount('#root')指定el的值。(2)、v.$mount("#root");
data的两种写法:
1、对象式;
2、函数式;
(学习组件时只能有函数式)
(注:Vue管理的函数,一定不能使用箭头函数,因为箭头函数this指向Window)
1、M:模型(Model):对应data中的数据;
2、V:视图(View):模板;
3、VM:视图模型(ViewModel):Vue的实例对象;
语法:Object.defineProperty(obj,prop,descriptor)
参数一:必须,目标对象;
参数二:必须,需要定义或修改的属性的名字;
参数三:必须,目标属性所拥有的特性——(1、这个属性用大括号括起来{};2、value设置属性的值,默认为underfined; 3、writetable是否可以重写(默认false); 4、enumerable目标属性是否可以被枚举(默认false); 5、configurable目标属性是否可以被删除或再次修改descriptor的这几个特性(默认false));
- <body>
- <script>
- let number = 18;
- let person = {
- name:'姓名',
- sex:'性别',
- }
- Object.defineProperty(person,'age',{
- get:function(){
- console.log("有人读取数据");
- return number;
- },
- set:function(value){
- console.log("有人修改了age属性值为:",value);
- number = value;
- }
- })
- console.log(person );
- </script>
- </body>
可以将get:function(){}和set:function()进行简化:
- <body>
- <script>
- let number = 18
- let person = {
- name:'张三',
- sex:'男',
- }
- Object.defineProperty(person,'age',{
- get(){
- console.log("有人读取了age属性");
- return number;
- },
- set(value){
- console.log("修改了age属性,值:",value);
- number = value;
- }
- })
- </script>
- </body>
数据代理:示例通过一个对象代理对另一个对象中属性的操作(读/写)
- <body>
- <script>
- let obj = {x:100};
- let obj2 = {y:200};
- Object.defineProperty('obj2','x',{
- get(){
- console.log("读取属性");
- return obj.x;
- }
- set(value){
- console.log("修改属性");
- obj.x = value;
- }
- })
- </script>
- </body>
小结:
1、Vue中数据代理:通过vm对象来代理data对象中属性的操作(读/写);
2、Vue中数据代理的好处:更方便操作data中的数据;
3、基本原理:通过Object.defineProperty()把data对象中所有属性添加到vm上。为每一个添加到vm上的属性,都指定一个getter、setter。在getter、setter内部去操作(读/写)data中对应的属性。
- <body>
- <div id="root">
- <h2>学校名称+{{name}}</h2>
- <h2>学校地址+{{address}}</h2>
- </div>
- </body>
- <script>
- Vue.config=productionTip=false;
- const vm =new Vue({
- el:'#root',
- data:{
- name:'尚硅谷',
- address:'科技园'
- }
- })
- </script>
小结:1、使用v-on:***或@xxx绑定事件,其中xxx是事件名;
2、事件的回调需要配置在methods对象中,最终会在vm中;
3、methods中配置的函数,不要使用箭头函数!否则this就不指向vm了;
4、methods中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象;
5、@click=‘demo’ 和 @click="demo($event)"效果一样,但后者可以传参;
(event:目标对象)
- <body>
- <div id ='root'>
- <h2>欢迎来到{{name}}学习</h2>
- <button v-on:click='showInfo'>点击提示信息</button>
- </div>
- </body>
- <script type="text/javascript">
- Vue.config.productionTip= false; //阻止Vue弹出生成提示;
- const vm = new Vue(
- el:"#root",
- data:{
- name:'尚硅谷'
- },
- methods:{
- showInfo(event){
- console.log(event);
- alert("同学你好");
- }
- showInfo(number,$event){
- console.log($event);
- console.log(number);
- }
- }
- )
- </script>
Vue中的事件修饰符:
1、prevent,阻止默认事件(preventDefault)
- <body>
- <div id="root">
- <h2>欢迎来到{{name}}学习</h2>
- <a href="http://www.baidu.com" @click.prevent="showInfo">点击提示信息</a>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false; //阻止提示vue生成提示
- new Vue(
- el:'#root',
- data:{
- name:'尚硅谷',
- },
- methods:{
- showInfo(e){
- //e.preventDefault();
- alert(同学你好);
- }
- }
- )
- </script>
2、stop,阻止事件冒泡;
- <body>
- <div id='root'>
- <h2>欢迎来到{{name}}</h2>
- <div class='demo1' @click='showInfo'>
- <div class="demo2" @click.stop="showInfo">点击弹出信息</div>
- </div>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- new Vue(
- el:'#root',
- data:{
- name:"尚硅谷"
- }
- methods:{
- showInfo(){
- alert("弹出信息");
- }
- }
- )
- </script>
3、once,事件只触发一次;
- <body>
- <div id="root">
- <h2></h2>
- <a href='http://www.baidu.com'@click.prevent='showInfo'>点击提示信息</a>
- <button @click.once='showInfo'>点击提示信息<>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- new Vue({
- el:'#root',
- data:{
- name:'尚硅谷',
- }
- })
-
- </script>
4、capture,使用事件的描述模式;
再捕获阶段直接处理,先执行1,再执行2;
- <body>
- <div id='root'>
- <div @click.capture='showInfo'>点击提示信息1
- <div @click=showInfo>点击提示信息2</div>
- </div>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- new Vue({
- el:'#root',
- data:{
- name:'尚硅谷',
- }
- })
- </script>
5、self,只有event.target是当前操作的元素时才触发事件;
6、passive:事件的默认行为立刻执行,无需等待事件回调执行完毕;
wheel为鼠标滚轮滚动事件;
scroll是滚动条滚动事件;
使用wheel时,若不使用passive命令则会等循环执行完后再滚动默认行为;使用后则会立刻执行,通知循环也执行。
- <body>
- <ul @wheel.passive='demo' class='list'>
- <li>1</li>
- <li>2</li>
- <li>3</li>
- </ul>
- </body>
- <script>
- Vue.config.productionTip=false;
- new Vue({
- el:'#root',
- data:{
- name:'尚硅谷'
- }
- methods:{
- demo(){
- for(let i =0;i<1000;i++){
- console.log('#');
- }
- console.log('打印完了');
- }
- }
- })
- </script>
1、Vue中常用的按键别名:
回车= >enter 上= >up
删除= >delete(捕获“删除”和“退格”) 下= >down
退出= >esc 左= >left
换行= >tab (特殊,必须配合keydown去使用) 右= >right
2、Vue未提供别名的按键,可以使用按键原始的key值去绑定,但要注意把组合单词变为这种形式:caps-locks;
3、系统修饰键(用法特殊):ctrl、alt、shift、meta
(1)需要配合keyup使用,按下修饰键的同时,再按下其他键,随后释放其他键,时间被触发;
(2)配合keydown使用,正常触发事件。
4、也可以使用keyCode去指定具体按键(不推荐);
5、可以自定义按 键名:Vue.config.keyCodes.自动以键名=键码,可以去定制按键别名
- <body>
- <div id='root'>
- <h2>欢迎来到{{name}}学习</h2>
- <input type='text'placeholder='按下回车提示输入'@keydown.enter='showInfo'>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- new Vue({
- el:'#root',
- data:{
- name:'尚硅谷',
- }
- methods:{
- showInfo(e){
- console.log(e.keyCode);
- }
- }
- })
- </script>
事件修饰符后边可以跟其他的修饰符:
- <body>
- <div>
- <a href='http://www.baidu.com' @click.stop.prevent='showInfo'>点击提示信息</a>
- </div>
- </body>
系统修饰键后边可以跟具体的键:
- <body>
- <h2></h2>
- <input type="text" placeholder="按下回车提示输入" @keyup.ctrl.y="showInfo">
- </body>
只要data中数据发生变化就会重新执行,解析模板。
- <body>
- <div id="root">
- 姓:<input type="text" v-model="firstName"><br/>
- 名:<input type="text" v-model="lastName"><br/>
- 全称:<span>{{fullName()}}</span> //加上括号在方法中表示调用方法的执行结果;在声明事件时,加不加括号都可以。
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- new vue({
- el:'#root',
- data:{
- firstName:'张',
- lastName:'三'
- },
- methods:{
- fullName(){ //普通函数在Vue中的this指向Vue实例
- return this.firstName+'-'+this.lastName;
- }
- }
- })
- </script>
小结:
1、定义:要用的属性不存在,要通过已有的属性计算得出;
2、原理:底层借助了Object.defineproperty方法提供的getter和setter;
3、get函数什么时候执行?
(1)初次读取时会执行一次;
(2)当依赖的数据发生改变时会被再次调用;
4、优势:与methods相比,内部会有缓存机制(复用)效率高,调试方便;
5、备注:
(1)计算属性最终会出现在vm上,直接读取使用即可;
(2)如果计算属性要修改,那必须写set函数去相应修改,且set中要引起计算时依赖的数据的变化;
- <body>
- <div id="root">
- 姓:<input type="text" v-model="firstName"><br/>
- 名:<input type="text" v-model="lastName"><br/>
- 全名:<span>{{fullName}}</span>
- 全名:<span>{{fullName}}</span>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm= new Vue({
- el:'#root',
- data:{
- firstName:'张',
- lastName:'三'
- },
- computed:{
- //通过计算得的数据给fullName
- fullName:{
- //get作用:当获取了fullName时,get就会调用,且返回值作为fullName值;
- // get什么时候调用? 1.当初次调用fullName时;2、所依赖的数据发生变化时;
- get(){
- console.log("get被调用了");
- return this.firstName+'-'+this.lastName;
- },
- set(value){
- console.log("set被调用");
- const arr = value.split('-'); //通过split()方法分隔字符串
- this.firstName = arr[0];
- this.lastName= arr[1];
- }
- }
- }
- })
- </script>
以上代码的获取数据的简写:(只读取不修改时才能使用)
把通过return返回的结果的值,交给fullName这个中。
- <body>
- <div id="root">
- 姓:<input type='text'v-model="firstName"><br/>
- 名:<input type='text'v-model="lastName"><br/>
- 全名:<span>{{fullName}}</span>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- new Vue({
- el:'#root',
- data:{
- firstName:'张',
- lastName:'三'
- },
- computed:{
- fullName(){ //相当于get方法
- console.log("调用函数")
- return this.firstName +'-'+ this.lastName
- }
- }
- })
- </script>
- <body>
- <div>
- <h2>今天天气很{{info}}</h2>
- <button @click="changeWeather">切换天气</button>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- conset vm= new Vue({
- el:'#root',
- data:{
- isHot:true,
- },
- computed:{
- info(){
- return this.isHot?'炎热':'凉爽';
- }
- },
- methods:{
- changeWeather(){
- this.isHot=!isHot;
- }
- }
- })
-
- </script>
在vue模板中可以在事件类型后边写简单的语句:
- <body>
- <div>
- <button @click='isHot=!isHot'></button>
- </div>
- </body>
小结:1、当监视的属性发生变化时,回调函数自动调用,进行相关操作;
2、监视的属性必须存在,才能进行监视;
3、监视的两种写法:
(1)new Vue 时传入watch配置;(在写代码时就确定监视哪个属性时使用)
(2)通过Vue实例化的vm.$watch坚持;(没有提前知道要具体监视哪个属性时)
- <body>
- <div>
- <h2>今天天气很{{info}}</h2>
- <button @click="changeWeather">切换天气</button>
- </div>
- </body>
- <script type="text/javascript">
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- isHot:true,
- },
- computed:{
- info:{
- return isHot?'炎热':'凉爽';
- }
- },
- methods:{
- changeWeather(){
- this.isHot=!isHot;
- }
- }
- 知道具体监视那个属性时
- watch:{ //监视方法
- isHot:{ //创建对象并传递值;
- immediate:true,
- handler(newValue,oldValue){
- console.log('isHot被修改了',newValue,oldValue);
- }
- }
- }
- })
- -------------------------------------
- 不知道具体监视那个属性时可以使用这个
- vm.$watch('isHot',{ //创建配置对象
- immediate:true, //初始化时就调用(默认为false)
- handler(newValue,oldValue){
- console.log('isHot被修改了',newValue,oldValue);
- })
- </script>
深度监视:
(1)Vue中的watch默认不监测对象内部值的改变(看一层)
(2)配置deep:true可以监测对象内部值的改变(多层)
备注:
(1)Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以(false);
(2)使用watch时根据数据的具体结构,决定是否采用深度监视;
- <body>
- <div id="root">
- <h3>a的值是{{a}}</h3>
- <button @click="numbers.a++">点击加一</button>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- numbers:{
- a=1,
- b=1
- }
- },
- watch:{
- //监视多级结构中,某个属性的变化;
- "number.a":{
- handler(){
- console.log("a已经改变了");
- }
- }
- -------------------
- number:{
- deep:true,
- handler(){
- console.log("内部有一个被改变了");
- }
- }
- }
- })
- </script>
简写方式:
方式一:通过new Vue时
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'root',
- data:{
- number:{
- a=1,
- b=1
- }
- },
- watch:{
- number(newValue,oldValue){
- console.log('number被修改了',newValue,oldValue);
- }
- }
- })
- </script>
方式二:通过实例化vm.$watch()方式
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'root',
- data:{
- number:{
- a=1,
- b=2
- }
- },
- })
- vm.$watch('number',(newValue,oldValue)={
- console.log("number中的值被改变了",newValue,oldValue);
- })
- </script>
一、computed能完成的功能,watch都可以完成;
二、watch能完成的功能,computed不一定能完成;(例如:定时器异步任务;)
两个重要的原则:
(1)所以被Vue管理的函数,最好写成普通函数,这样this所指向的才是vm或组件实例对象;
(2)所有不被vue管理的函数(定时器,Ajax回调函数,promise回调函数),最好使用箭头函数,这样可以使得this指向vm 实例或者组件实例。
姓名案例(computed写法):
- <body>
- <div id='root'>
- 姓:<input type='text' v-model="firstName"><br/>
- 名:<input type='text' v-model="lastName"><br/>
- 全名:<span>{{fullName}}</span>
- </div>
- </body>
- <script>
- Vue.config.productionTip =false;
- const vm = new Vue({
- el"#root",
- data:{
- firstName:'张',
- lastName:'三'
- },
- computed:{
- fullName(){
- console.log('get被调用了');
- return this.firstName + '-' + this.lastName;
- }
- }
- ])
- </script>
例如姓名案例(watch写法):
- <body>
- <div id='root'>
- 姓:<input type='text' v-model="firstName"><br/>
- 名:<input type='text' v-model="lastName"><br/>
- 全名:<span>{{fullName}}</span>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm=new Vue({
- el:'#root',
- data:{
- firstName:'张',
- lastName:'三',
- fullName:'张-三'
- },
- watch:{
- firstName(fName){
- setTimeout(()=>{
- console.log(this); //此时函数为箭头函数,没有具体指向,往外边找,
- //外边为普通函数,所以指向Vm实例了
- this.fullName=fName + '-' + this.lastName;
- },1000)
- },
- lastName(lname){
- this.fullName=this.firstName + '-' + lname;
- }
- }
- })
-
- </script>
方式一:字符串写法,适用于:样式的类名不确定,需要动态指定。
- <body>
- <div id="root">
- <div class="basic" :class="mood" @click="changeMood">{{name}}</div>
- </div>
- </body>
- <script type="text/javascript">
- Vue.config.productionTip=false;
- new Vue({
- el:'#root',
- data:{
- name:'尚硅谷',
- mood:'normal' //动态指定样式为:normal
- },
- methods:{
- changeMood:{
- this.mood='happy'; //指定Vue对象,点击时切换样式为happy
- }
- }
- --------------------------------------------------
- methods:{
- changeMod(){
- const arr = ['happy','sad','normal']
- const indes = Math.floor(Math.random()*3)
- this.mood= arr[indes]
- }
- }
- })
- </script>
方式二: 数组写法,适用于:要绑定的样式个数不确定,名字也不确定.
- <body>
- <div id="root">
- <div class="basic" :class="classArr">{{name}}</div>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm= new Vue({
- el:'#root',
- data:{
- name:'尚硅谷',
- classArr:['atguigu1','atguigu2','atguigu3']
- },
- })
- </script>
方式三:对象对法,适用于:要绑定的样式的个数确定,名字也确定,但要动态决定用不用。
- <body>
- <div id="root">
- <div class="basic" :class="classObj">{{name}}</div>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'尚硅谷',
- data:{
- name:'',
- classObj:{ //定义一个对象,里边包含样式是否使用
- red:true,
- blue:false
- }
- }
- })
- </script>
(1)Style对象样式:
- <body>
- <div id="root">
- <div class='basic' :style:'styleObj'>{{name}}</div>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- conse vm=new Vue({
- el:'#root',
- data:{
- styleOby:{
- fontSize:'50px',
- color:'red'
- }
- }
- })
- </script>
(2)style数组绑定样式
- <body>
- <div id="root">
- <div class="basic" :style="styleArr">{{name}}</div>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm=new Vue({
- el:'#root',
- data:{
- name:'尚硅谷',
- styleArr:[
- {
- fontSize:'50px',
- color:'red'
- },
- {
- backgroundColor:'blue'
- }
- ]
- }
- })
- </script>
Vue——添加样式小结:
写法:class="***",***可以是字符串,数组和对象。
字符串方式适用于:类名不确定,要动态获取;
对象写法适用于:要绑定多个样式,名气不确定,个数也不确定;
数组方式适用于:要绑定多个样式,名字确定,个数确定,但不确定是否使用;
:style="{fontSize:***}",其中***是动态的;
:style="[a,b]",其中a,b是样式对象;
一、使用v-show做条件渲染
(1)为true时显示,为false时隐藏(在结构中不消失);
(2)当表达式为true时显示,否则隐藏;
- <body>
- <div id='root'>
- <h2 v-show='false'></h2>
- <h2 v-show="1===1"></h2>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm=new Vue({
- el:'#root',
- data:{
- name:'尚硅谷',
- }
- })
- </script>
二、使用v-if做条件渲染
此时v-if如果是假值则隐藏,且执行后结构中也看不到;
- <body>
- <div id="root">
- <h2>当前值为:{{n}}</h2>
- <button @click="n++">点击加1</button>
- <div v-if='false'>隐藏,结构中也看不到</div>
- <div v-if="n===1">等于一时显示</div>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- name:'尚硅谷'
- }
- })
- </script>
这样判断样式,只执行其中符合的一个,成功后则退出;
- <body>
- <div id="root">
- <h2>当前值为:{{n}}</h2>
- <button @click="n++">点击n加一</button>
- <div v-if="n===1">等于一显示</div>
- <div v-else-if="n===2">等于二时显示</div>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm= new Vue({
- el:'#root',
- data:{
- name:'尚硅谷'
- }
- })
- </script>
v-if...可以和template一起使用,可以让符合条件的执行语句并且不会影响结构。
- <body>
- <div id="root">
- <h2>当前值为:{{n}}</h2>
- <button @click="n++">点击n加一</button>
- <div v-if="n===1">等于一显示</div>
- <template v-if="n===2">
- <h2>显示</h2>
- <h2>显示</h2>
- </template>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm= new Vue({
- el:'#root',
- data:{
- name:'尚硅谷'
- }
- })
- </script>
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一定可以获取;
通过v-for遍历渲染数组:
- <body>
- <div id='root'>
- <ul>
- <li v-for="p in person" :key="p.id"> //当vue中使用v-for时,要使用唯一的标识
- // key="p.id"
- {{p.name}}--{{p.age}}
- </li>
- ----------------------------
- //前边形参可以使用两个参数 ,第一个代表得到的数据,第二个是索引值
- <li v-for="(p,index) in persons" :key="p.id/index">
- {{p.value}}----{{p.index}}
- </li>
- </ul>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- person:[
- {id:'01',name:'张三',age:20},
- {id:'02',name:'李四',age:18},
- {id:'03',name:'王五',age:25}
- ]
- }
- })
- </script>
通过v-for遍历对象数据:
"a"位置参数表示数据值,(key:value)中的value;
"b"位置参数表示数据键,(key:value)中的key;
- <body>
- <div id="root">
- <h2>汽车信息</h2>
- <ul>
- <li v-for="(a,b)in car" :key="b">
- {{b}}--{{a}}
- //输出结果为:name--红旗
- //price--20
- //color:黑色
- </li>
- </ul>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- car:{
- name:'红旗',
- price:'20',
- color:'黑色'
- }
- }
- })
- </script>
v-for遍历字符串:
- <body>
- <div id="root">
- <h2>汽车信息</h2>
- <ul>
- <li v-for="(char,index)in car" :key="index">
- {{char}}--{{index}}
- //输出结果为:h--0,e--1这样的
- </li>
- </ul>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- str:'hello'
- }
- })
- </script>
v-for小结:
1、用于列表数据;
2、语法:v-for="(item,index) in ***" :key="某个唯一值"
3、可以遍历:数组,对象、字符串(少)、指定次数(很少);
- <body>
- <div id="root">
- <h2>人员编标遍历</h2>
- <button @click.once="add">添加一个信息</button>
- <ul>
- <li v-for="(p,index) of persons" :key="index">
- {{p.name}}--{{p.age}}
- </li>
- <li></li>
- </ul>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm= new Vue({
- el:'#root',
- data:{
- person:[
- {id:'001',name:'张三',age:20},
- {id:'002',name:'李四',age:18},
- {id:'003',name:'王五',age:25},
- ]
- },
- methods:{
- add(){
- const p = {id:'004','新信息',24}
- this.persons.unshift(p);
- }
- }
- })
- </script>
- <body>
- <div id="root">
- <h2>人员编标遍历</h2>
- <button @click.once="add">添加一个信息</button>
- <ul>
- <li v-for="(p,index) of persons" :key="p.id">
- {{p.name}}--{{p.age}}
- </li>
- <li></li>
- </ul>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm= new Vue({
- el:'#root',
- data:{
- person:[
- {id:'001',name:'张三',age:20},
- {id:'002',name:'李四',age:18},
- {id:'003',name:'王五',age:25},
- ]
- },
- methods:{
- add(){
- const p = {id:'004','新信息',24}
- this.persons.unshift(p);
- }
- }
- })
- </script>
执行结果为:
执行原理为:
(面试题:react、vue中key的作用,内部原理)
一、虚拟DOM中key的作用:
key是虚拟DOM对象的表示,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的对比;
比较规则:
1、旧虚拟DOM中如果找到了与新虚拟DOM中相同的key:
(1)、若虚拟DOM中内容没变,直接使用之前的真是DOM;
(2)、若虚拟DOM中内容变了,则生成新的真实DOM,随后替换之前页面中的真 是DOM。
2、旧虚拟DOM中未找到与新虚拟DOM相同的key:创建新的真实DOM,随后渲染到页面中。
二、用index作为key时:
1、若对数据进行逆序添加、逆序删除等破坏顺序的操作:会产生没有必要的真实DOM更新===》界面效果没问题,但效率低;
2、如果结构中包括输出类DOM,会产生错误的DOM更新===》界面有问题;
三、开发中的如果选择:
1、最好使用每条数据中唯一的值作为唯一标识key,比如id,手机号等;
2、如果不存在对数据进行逆序添加、删除等破坏顺序的操作,仅用于渲染列表用于展示,使用index(索引)作为key也可以。
一、通过数据监视实现:
- <body>
- <div id='root'>
- <h2>过滤列表</h2>
- <input type='text' placeholder="请输入信息" v-model="keyWords">
- <ul>
- <li v-for="(p,index)of filPerons" :key="index">
- {{p.name}}--{{p.age}}
- </li>
- </ul>
- </div>
- </body>
- <script type='text/javascript'>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- keyWords:'',
- persons:[
- {id:'001',name:'冬天',age:18},
- {id:'002',name:'立冬',age:25},
- {id:'003',name:'立春',age:20}
- ],
- filPerons:[]
- },
- watch:{ //监视完全写法
- keyWords:{
- immediate:true,
- handler(val){
- this.filPerons = this.persons.filter((p)=>{
- return p.name.indexOf(val) !==-1
- })
- }
- }
- }
- })
- </script>
二、通过数据计算:
- <body>
- <div id='root'>
- <h2>过滤列表</h2>
- <input type='text' placeholder="请输入信息" v-model="keyWords">
- <ul>
- <li v-for="(p,index)of filPersons" :key="index">
- {{p.name}}--{{p.age}}
- </li>
- </ul>
- </div>
- </body>
- <script type='text/javascript'>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- keyWords:'',
- persons:[
- {id:'001',name:'冬天',age:18},
- {id:'002',name:'立冬',age:25},
- {id:'003',name:'立春',age:20}
- ]
- },
- computed:{
- filPersons(){
- return this.persons.filter((p)=>{
- return p.name.indexOf(this.keyWords) !==-1
- }
- })
- }
- })
- </script>
arr.sort( (a,b) => { });
数组排序,a-b为升序;b-a为降序;
- <body>
- <div id='root'>
- <h2>过滤列表</h2>
- <input type='text' placeholder="请输入信息" v-model="keyWords">
- <button>年龄升序</button>
- <button>年龄降序</button>
- <button>原顺序</button>
- <ul>
- <li v-for="(p,index)of filPersons" :key="index">
- {{p.name}}--{{p.age}}
- </li>
- </ul>
- </div>
- </body>
- <script type='text/javascript'>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- keyWords:'',
- sortType:0, //0代表原顺序,1代表升序,2代表降序
- persons:[
- {id:'001',name:'冬天',age:18},
- {id:'002',name:'立冬',age:25},
- {id:'003',name:'立春',age:20}
- ],
- filPerons:[]
- },
- computed:{
- filPersons(){
- const arr = this.persons.filter((p)=>{
- return p.name.indexOf(this.keyWords) !==-1
- }
- if(this.sortType !== 0){
- arr.sort((a,b)=>{
- return this.sortType ===1 ? a.age - b.age : b.age-a.age
- })
- }
- return arr;
- })
- }
- })
- </script>
- <body>
- <div id="root">
- <h2>学生信息</h2>
- <button @click='student.age++'>年龄加一</button>
- <button @click="addSex">添加性别属性。默认值:男</button>
- <button @click="student.sex='未知'">修改性别</button>
- <button @click="addFriend">在列表首位添加一个朋友</button>
- <button @click="updataFriend">修改第一个朋友的名字:张三</button>
- <button @click="addHobby">添加一个爱好</button>
- <button @click="updataHobby">修改第一个爱好者:开车</button>
-
- <h3>姓名:{{student.name}}</h3>
- <h3>年龄:{{student.age}}</h3>
- <h3 v-if:"student.sex">性别:{{student.sex}}</h3>
- <h3>爱好:{{student.hobby}}</h3>
- <ul>
- <li v-for="(h,index) in student.hobby" :key="index">{{h}}</li>
- </ul>
- <h3>朋友们:</h3>
- <ul>
- <li v-for="(f,index) in student.friends" :key="index">
- {{f.name}}--{{f.age}}
- </li>
- </ul>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- conse vm= new Vue({
- el:'#root',
- data:{
- student:{
- name:'tom',
- age:20,
- hobby:["游泳","看书","敲代码"],
- friends:[
- {name:'jerry',age:18},
- {name:'andi',age:20}
- ]
- }
- },
- methods:{
- addSex(){
- vue.set(this.student,'sex','男') //或者 vm.$set(this.student,'sex','女');
- },
- addFriend(){
- this.student.friends.unshift({name:'aaa',age:25})
- },
- updataFriend(){
- this.student.friends[0].name="jack";
- this.student.friends[0].age=16;
- },
- addHobby(){
- this.student.hobby.push('学习');
- },
- updataHobby(){
- this.sdudent.hobby.splice(0,1,"开车")
- ----------------------------------
- vue.set(this.student.hobby,0,"开车");
- -----------------------------------
- vm.$set(this.student.hobby,0,"开车");
- }
- }
- })
-
- </script>
一、Vue会监视data中的所有层次的数据。
二、通过setter实现监视,且要在new.Vue时就传入要检测的数据:
(1)对象中后追加的属性,Vue默认不做响应式处理;
(2)如需要给后添加的属性做响应式,需要使用如下API:
- Vue.set(target, properyName/index, value)
- 目标 追加的属性 追加属性的值
- 或者:
- vm.$set(target, propertyName/index, value);
注意:Vue.set() 和 vm.$set() 不能修改vm 或者 vm的根数据对象添加属性!!
三、通过包裹数组更新元素的方法实现,本质就做了两件事:
(1)调用原生对应的方法对数组进行更新;
(2)重新解析模板,进而更新页面;
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- persons:[
- {id:'001',name:'张三',age:20,sex:'女'},
- {id:'002',name:'王五',age:22,sex:'男'},
- {id:'003',name:'李四',age:18,sex:'女'},
- ]
- },
- methods:{
- upda(){
- this.persons.splice(0,1,{id:'001',name:'学习',age:25,sex:'男'})
- }
- }
- })
- </script>
(1)、使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、 reverse();
(2)、Vue.set() 或者 vm.$set();
<body> <div id="root"> <form @submit.prevent="demo"> //阻止默认提交行为, 账号:<input type='text' v-model.trim="user"><br/> 密码:<input type='password' v-model.trim="password"><br/> 年龄:<input type="number" v-model.number="age"><br/> 性别: 男:<input type="radio" name="sex" v-model="man" value="man"><br/> 女:<input type="radio" name="sex" v-model="woman" value="woman"><br/> 爱好: 学习<input type="checkbox" v-model="hobby" value="stydy"><br/> 游戏<input type="checkbox" v-model="hobby" value="game"><br/> 看书<input type="checkbox" v-model="hobby" value="readbook"><br/> 所属校区 <select v-model="city"> <option value="">请选择校区</option> <option value="beijing">北京</option> <option value="shanghai">上海</option> <option value="shenzhen">深圳</option> <option value="wuhan">武汉</option> <option value="tianjin">天津</option> </select> 其他信息<textarea v-model.lazy="other"></textarea> <input type="checkbox" v-model="agree">阅读并接收用户协议<a href="https://www.baidu.com">用户协议</a> <button>提交</button> </form> </div> </body> <script> Vue.config.productionTip=false; const vm = new Vue({ el:'#root', data:{ user:'', password:'', sex:'man', hobby:[], city:'beijing', other:'', agree:'', }, methods:{ demo:{ console.log(this._data); //方式一 --------------------- // console.log(JSON.stringify(this.userInfo)); 此方式需要把信息放入一个 userInfo对象里边,并需要在全部的v-model前边加userInfo前缀; } } }) </script>
若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。
若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
若:<input type="checkbox">
1、没有配置Input的value属性,那么收集的就是checked(勾选或者未勾选,true或false)
2、配置Input的value属性:
(1)v-model的初始值是非数组,那么收集的就是checked值(true或false)
(2)v-model的初始值是数组,那么收集的就是value组成的数据;
备注:v-model的三个修饰符:
(1)lazy:失去焦点收集数据;
(2)Number:输入字符串转为有效数字(一般type="number" v-model.number同时出现)
(3)trim:输入的首位空格过滤;
方式一:计算属性方式和构造方法(局部)
- <body>
- <div id="root">
- <h2>显示格式化后的时间</h2>
- <h3>现在是:{{fmtTime}}</h3>
- <h3>现在是:{{getFmtTime()}}</h3>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- time:1621561277603
- },
- computed:{ //计算属性方式
- fmtTime(){
- return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss') //返回调用dayjs方法
- }
- },
- methods:{
- getFmtTime(){
- return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss') //返回调用dayjs方法
- }
- }
- })
- </script>
方式二:过滤器方式(局部)
- <body>
- <div id="root">
- //不包含参数的过滤器
- <h3>现在是:{{time | timeFormater}}</h3>
- ---------------------------------------
- //有参数的过滤器
- <h3>现在是{{time | timeFormater('YYYY_MM_DD')}}</h3>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- time:1621561277603
- },
- filters:{
- timeFormater(value,str='YYYY-MM-DD HH:mm:ss'){ //如果传递的是不包含参数的使用后边的参数,如果传递的包含参数则使用传递的
- return dayjs(value).format(str); //format计划,设计
- }
- }
- --------------------------------------------
- filters:{
- timerFormater(value){
- return dayjs(value).format('yyyy年mm月dd日 hh:mm:ss')
- }
- }
- })
- </script>
多个过滤器联动(局部)
- <body>
- <div id="root">
- //不包含参数的过滤器
- <h3>现在是:{{time | timeFormater}}</h3>
- ---------------------------------------
- //有参数的过滤器
- <h3>现在是{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h3>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- time:1621561277603
- },
- filters:{
- timeFormater(value,str='YYYY-MM-DD HH:mm:ss'){ //如果传递的是不包含参数的使用后边的参数,如果传递的包含参数则使用传递的
- return dayjs(value).format(str);
- },
- mySiice(value){
- return value.slice(0,4) //从得到的值从截取四个长度
- }
- }
- })
- </script>
全局过滤器:
- <body>
- <div id="root">
- //不包含参数的过滤器
- <h3>现在是:{{time | timeFormater}}</h3>
- ---------------------------------------
- //有参数的过滤器
- <h3>现在是{{time | timeFormater('YYYY_MM_DD')}}</h3>
- </div>
-
- //模拟使用全局过滤器
- <div id='root2'>
- <h2>{{msg | mySlice}}</h2>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- //声明全局过滤器
- Vue.filter('mySlice',function(value){
- return value.slice(0,4)
- })
- const vm = new Vue({
- el:'#root',
- data:{
- time:1621561277603
- },
- filters:{
- timeFormater(value,str='YYYY-MM-DD HH:mm:ss'){ //如果传递的是不包含参数的使用后边的参数,如果传递的包含参数则使用传递的
- return dayjs(value).format(str);
- },
- mySlice(value){
- return value.slice(0,4)
- }
- }
- })
- new Vue({
- el:'#root2',
- data:{
- msg:'hello,word'
- },
- mySiice(value){
- return value.slice(0,4) //从得到的值从截取四个长度
- }
- })
- </script>
过滤器小结:
定义:对要显示的数据进行特定的格式化后再显示(使用一些简单的处理)。
语法:
(1)注册过滤器:Vue.filter(name,callback) 或 new Vue { filters:{ } }
(2)使用过滤器:{{xxx | 过滤器名称}} 或者 v-bind: 属性=" xxx | 过滤器名称 "
两种用法: 一、 用在差值语法中; 二、 v-bind中
备注:
(1)过滤器可以接收额外参数、多个过滤器可以串联;
(2)并不会改变原来数据,而是产生新的对应的数据;
我们之前学过的指令:
v-bind:单向数据绑定,可简写":";
v-model: 双向数据绑定;
v-for:遍历数组/对象/字符串;
v-on:绑定事件监听,可简写为:@;
v-if:条件渲染(动态控制节点是否存在;)
v-else: 条件渲染(动态控制节点是否存在)
v-show:条件渲染(动态控制节点是否存在)
v-text指令:
- <body>
- <div id= "root">
- <div>{{name}}</div>
- <div v-text="name">被替换</div> //v-text中的内容会替换到节点中内容
- </div>
- </body>
- <script>
- Vue.config.productionTip='false';
- const vm = new Vue({
- el:'#root',
- data:{
- name:'尚硅谷',
- str:'你好啊'
- }
- })
- </script>
1、作用:向其所在的节点中渲染文本的内容。
2、与差值语法不同的是:v-text会替换到节点中的内容;差值语法{{ }}不会;
- <body>
- <div id="root">
- <div v-html="str"><>
- <div v-html="str2"></div>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- name:'尚硅谷',
- str2:'<h3>你好</h3>',
- }
- })
- </script>
小结:
v-html指令:
1、作用:向指定的节点中渲染包含HTML结构的内容;
2、与差值语法区别:
(1)v-html会替换掉节点中所有的内容,{{ }}不会;
(2)v-html可以识别HTML结构;
3、注意:
(1)在网站上动态渲染任意HTML是非常危险的,容易被XSS共计;
(2)一定要在可信的内容上使用v-html(永远不要用在用户提交的内容上)
五秒钟之前不显示结构,五秒钟后显示调用Vue.js 完成后的样式。
- <head>
- <style>
- [v-cloak]{ //属性选择器,选择所有的v-cloak属性
- display:none
- }
- </style>
- </head>
- <body>
- <div id="root">
- <h2 v-clock>{{name}}</h2>
- </div>
- <script type="text/javascript" src="https:www.baidu.com/resours/5s/vue.js">五秒钟后执</script>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root';
- data:{
- name:'尚硅谷'
- }
- })
- </script>
小结:
1、本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删除v-cloak属性;
2、使用css配合v-cloak可以解决网速慢时页面展示{{ **}}的问题;
小结:
(1)v-once所在节点在初次动态渲染后,就视为静态内容了。
(2)以后的数据的改变不会引起v-once所在结构的更新,可以用于优化性能
- <body>
- <div id="root">
- <h2 v-once>初始化值{{n}}</h2>
- <h2>初始值是:{{n}}</h2>
- <button @click="add">点击加1</button>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- n:1
- },
- methods:{
- add(){
- return this.n++;
- }
- }
- })
- </script>
- <body>
- <div id="root">
- <h2 v-pre>vue很简单</h2>
- <button>使用v-pre后跳过h2的编译过程</button>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- n:1;
- }
- })
- </script>
小结:
v-pre指令:(1)可以跳过所在节点的编译过程;
(2)可利用它跳过:没有使用指令语法、没有使用差值语法的节点,会加快编译;
(自定义指令明不需要加“v-”)
方式一:函数式
- <body>
- <div id="root">
- <h2>{{name}}</h2>
- <h2>当前值是:<span v-text='n'></span></h2>
- <h2>放大十倍:<span v-big='n'></span></h2>
- <button @click="n++">点击加1</button>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false
- onst vm = new Vue({
- el:'#root',
- data:{
- name:'尚硅谷',
- n:1
- },
- directives:{
- big(element,binding){
- console.log('big');
- element.innerText = binding.value *10;
- }
- }
- })
- </script>
(1)指令与元素成功绑定时(一上来);
(2)指令所在的模板被重新解析时。
方式二:对象式
- <body>
- <div id ="root">
- <h2>{{name}}</h2>
- <h2>当前n的值是:<span v-text="n"></span></h2>
- <h2>放大后n的值是:<span v-big="n"></span></h2>
- <button>点击增加</button>
- <input type = "text" v-fbind:value="n">
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm= new Vue({
- el:'#root',
- data:{
- name:'尚硅谷',
- n:1
- },
- directives:{
- big:(element,binding){ //简写方式,相当于只执行了指令与元素成功绑定的步骤,和,指令所在被重新解析时;这两
- element.innerText = binding.value*10;
- },
- fbind:{ //对象方式调用
- bind(element,binding){ //指令与元素成功绑定时(一上来);
- element.value=binding.value;
- },
- inserted(element,binding){ //指令所在元素被插入页面时;
- element.focus();
- },
- update(element,binding){ //指令所在的模板被重新解析时;
- element.value=binding.value;
- }
- }
- }
- })
- </script>
(1)局部指令
或:
Vue.directive(指令名,回调函数)
(1)bind:指令与元素成功绑定时调用;
(2)inserted:指令所在元素被插入页面时调用
(3)update:指令所在模板结构贝重新解析时调用;
指令定义时不加"v-",但使用时要加"v-"
指令明如果是多个单词,要使用kebab-case命名方式。
自定义指令this指向问题:this指向的是window
自定义指令多个单词组成的用"-"分隔,同时要用完全写法;
- <body>
- <div id="root">
- <h2>当前的n的值是:<span v-text='n'></span></h2>
- <h2>放大十倍后是:<span v-big-number="n"></span></h2>
- <button @click="n++"></button>
- <br/>
- <input type='text' v-fbind:value="v">
- </div>
- </body>
- <script>
- Vue.config.productionTip=flase;
- const vm = new Vue({
- el:"#root",
- data:{
- name='尚硅谷',
- n:1
- },
- directives:{
- 'big-nameber'(element,binding){
- //如果自定义名字有多个单词组成,用“-”符号隔开,则如要原写法;
- element.innerText = binding.value * 10;
- },
- fbind:{
- bind(element,binding){
- console.log("fbind-bind",this)
- element.value = binding.value;
- },
- inserted(element,binding){
- console.log("fbind-inserted",this);
- element.focus();
- },
- update(){
- console.log("fbind-update",this)
- //上述三个自定义指令中this指window
- element.value=binding.value;
- }
- }
- }
- })
- </script>
定义全局指令时:
- <body>
- <div id="root">
- <h2>当前的n的值是:<span v-text='n'></span></h2>
- <h2>放大十倍后是:<span v-big-number="n"></span></h2>
- <button @click="n++"></button>
- <br/>
- <input type='text' v-fbind:value="v">
- </div>
- </body>
- <script>
- Vue.config.productionTip=flase;
- Vue.directive('fbind',{
- bind(element,binding){
- console.log("fbind-bind",this)
- element.value = binding.value;
- },
- inserted(element,binding){
- console.log("fbind-inserted",this);
- element.focus();
- },
- update(){
- console.log("fbind-update",this)
- //上述三个自定义指令中this指window
- element.value=binding.value;
- }
- })
- const vm = new Vue({
- el:'#root',
- data:{
- name:'尚硅谷',
- }
- })
- </script>
引出:生命周期
小结:
(1)生命周期又称为:生命周期回调函数、生命周期函数、生命周期钩子;
(2)作用:Vue在关键时刻帮我们调用一些特殊名称的函数;
(3)生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的;
(4)生命周期函数中的this指向的是Vm或组件实例对象;
- <body>
- <div id="root">
- <h2 v-if="a">你好</h2>
- <h2 :style="{opacity}">欢迎学习Vue</h2>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- a:false,
- opacity:1
- },
-
- //Vue完成模板的解析后并把初始的真是DOM元素放入界面后(挂载完毕)调用mounted
- mounted(){
- console.log("执行了生命周期函数");
- setInterval(()=>{
- this.opacity -=0.01
- if(this.opacity <=0) this.opacity=1
- },1000)
- },
- })
- </script>
Vue——生命周期挂载流程
(1组)创建(beforeCreate 、create)
(2组)挂载(beforeMounted、mounted):发送Ajax请求、启动定时器、绑定自定义事件等【初始化操作】
(3组)更新(beforeUpdate、update)
(4组)销毁(beforeDestory、destory):清除定时器、解绑自定义事件、取消订阅等【收尾工作】
使用清除定时器方式
- <body>
- <div id="root">
- <h2 :style="{opacity}">欢迎学习,字体颜色变换</h2>
- <button @click="stop">点击停止变化</button>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const vm = new Vue({
- el:'root',
- data:{
- opacity:1
- },
- methods:{
- stop(){
- clearInterval(this.timer);
- }
- },
- mounted(){
- console.log('mounted',this)
- this.timer = setInterval(()=>{
- this.opacity -=0.01
- if(this.opacity) <=0 this.opacity=1
- },15)
- }
- })
- </script>
使用销毁声明周期方式
- <body>
- <div id="root">
- <h2 :style="{opacity}">欢迎学习,字体颜色变换</h2>
- <button @click="stop">点击停止变化</button>
- </div>
- </body>
- <script>
- Vue.config.productiontip=false;
- const vm = new Vue({
- el:'#root',
- data:{
- opacity:1
- },
- methods:{
- stop(){
- this.$destroy() //点击销毁生命周期
- }
- },
- mounted(){ //生命周期——挂载
- console.log('mounted',this)
- this.timer = setInterval(()=>{
- console.log('setInterval')
- this.opacity -=0.01
- if(this.opacity <=0) this.opacity =1
- },15)
- },
- beforeDestory(){ //生命周期——销毁之前
- console.log("销毁之前")
- clearInterval(this.timer)
- }
- })
- </script>
一、常用的生命周期钩子:
(1)mounted:发送Ajax请求,启动定时器、绑定自定义事件、订阅消息等【初始化操作】
(2)beforedestroy:清楚定时器、解绑自定义事件、取消订阅消息等【收尾工作】
二、关于销毁Vue实例:
(1)、销毁后借助Vue开发者工具看不到任何消息;
(2)、销毁后自定义事件会失效,但看原生DOM事件依然有效;
(3)、一般不会再beforeDestroy操作数据,因为即使操作数据,也不会再触发更多新流程了。
定义:实现应用中局部功能代码和资源的集合。
创建局部组件:
- <body>
- <div id="root">
- <h1></h1>
- //第三步:编写组件标签
- <hr/>
- <xuexiao></xuexiao>
- <hr/>
- <xuesheng></xuesheng>
- </div>
-
- <div id="root2">
- <hello></hello>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- 第一步:创建组件
- const schools = Vue.extend({ //组件定义不能有el配置项,最所有组件都要被一个vm管理
- template:`
- <div>
- <h2>学校名称:{{schoolName}}</h2>
- <h2>学校地址:{{address}}</h2>
- <button @click="al">点击弹出名称</button>
- </div>
- `,
- data(){
- return{
- schoolName:'尚硅谷',
- address:'北京'
- }
- }
- }),
-
- const students = Vue.extend({
- template:`{
- <h2>学生名字{{studentName}}</h2>
- <h2>学生年龄{{age}}</h2>
- }`
- data(){
- return{
- studentName:'小红',
- age:'18'
- }
- }
- }),
- const vm = new Vue({
- el:'#root',
- 第二步:注册组件
- components:{ //注册组件们
- xuexiao : schools, //key:value 定义最终的组件名字
- xuesheng : students
- }
- })
- <script>
创建全局组件:
- <body>
- <div id="root2">
- <hel></hel>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const hello = Vue.extend({ //第一步创建组件
- template:`
- <div>
- <h2>你好,注册全局组件{{name}}</h2>
- </div>
- `,
-
- data(){
- return{
- name:'Tom',
- }
- }
- }),
- Vue.component("hel",hello)
-
- const vm = new Vue({
- el:'#root2',
- })
- </script>
小结:
Vue中使用组件的三个步骤:
(1)定义组件;
(2)注册组件;
全局注册: 局部注册:
(3)使用组件(写组件的标签)
(一)、如果定义一个组件:
使用Vue.extend(options组件名)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别:
区别如下:
1、el配置不要写——最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
2、data必须写成函数——避免组件被复用时,数据存在引用关系。
备注:使用template可以配置组件结构。
二、如果注册组件:
(1)局部组件:靠new Vue的时候传入components选项;
(2)全局注册:靠Vue.component(“组件名”,组件)
三、编写组件标签:
1、<school></school>
- <body>
- <div id="root">
- <h2>{{msg}}</h2>
- //编写组件标签
- //组件标签方式一
- <xuexiao><xuexiao>
- //组件标签写法方式二
- <xuexioa/>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- //定义组件
- const s = Vue.extend({
- name:'vue开发者工具',
- template:`
- <div>
- <span>定义组件{{name}}</span>
- </div>
- `,
- data(){
- return {
- name:'组件的参数'
- }
- }
- })
- const vm = new Vue({
- el:'#root',
- data:{
- msg:'欢迎学习Vue'
- },
- //注册组件
- components:{
- xuexiao:s //接收从组件传递的值
- }
- })
- </script>
第一种写法(首字母小写):school
第二种写法(首字母大写):School
关于组件名——多个单词组成:
第一种写法(kebab-case命名):my-school
第二种写法(CameCase命名):MySchool(需要Vue脚手架支持
备注:(1)组件命名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
(2)可以使用name配置项指定组件在开发者工具中呈现的名字。
第一种写法:<school></school>
第二种写法:<school/>
备注:不使用脚手架时,第二种方式可能会导致后序组件不能渲染。
const school = Vue.extend(options)可简写为:const school = options
- <body>
- <div id="root">
- <school></school>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const student = Vue.extend({
- name:'student',
- template:`
- <div>
- <h2>姓名{{name}}</h2>
- <h2>年龄{{age}}</h2>
- </div>
- `,
- data(){
- return{
- name:'张三',
- age:25
- }
-
- }
- }),
- const school= Vue.extend({
- name:'school',
- template:`
- <div>
- <h2>学校姓名{{name}}</h2>
- <h2>学生数量{{number}}</h2>
- <student></student>
- </div>
- `,
- data(){
- return{
- name:'尚硅谷',
- number:100
- }
- },
- components:{
- student
- }
- }),
- new Vue({
- el:'#root',
- components:{
- school;
- }
- })
- </script>
App合并
- <body>
- <div id="root">
- <app></app>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const student = Vue.extend({
- name:'Student',
- template:`
- <div>
- <h2>学生姓名{{name}}</h2>
- </div>
- `,
- data(){
- return{
- name:'张三'
- }
- }
- }),
- const school = Vue.extend({
- name:'School',
- template:`
- <div>
- <h2>学校名称:{{name}}</h2>
- <h2>学校地址:{{address}}</h2>
- <student></student>
- </div>
- `,
- components:{ //注册学生组件
- student
- }
- data(){
- return{
- name:'尚硅谷',
- address:'北京'
- }
- }
- }),
- const app = Vue.extend({
- name:'App',
- template:`
- <div>
- <school></school>
- </div>
- `,
- components:{ //注册学校组件
- school
- }
- }),
- const vm = new Vue({
- el:'#root',
- components:{
- app
- }
- })
- </script>
- <body>
- <div id="root">
- <school></school>
- <hello></hello>
- </div>
- </body>
- <script>
- Vue.config.productionTip=false;
- const school = Vue.extend({
- name:'school',
- template:`
- <div>
- <h2>学校名称{{name}}</h2>
- <button @click='showName'>点击弹出名称</button>
- </div>
- `,
- data(){
- return{
- name:'尚硅谷'
- }
- },
- methods:{ //定义一个方法,弹出当前对象,当前对象this指向VueComponent
- showName(){
- alert(this.name);
- }
- }
- }),
- const hello = Vue.extend({
- name:'hello',
- template:`
- <div>
- <h3>与school同级的对象{{name}}</h3>
- </div>
- `,
- data(){
- return{
- name:'构造函数';
- }
- },
- })
- const vm = new Vue({
- el:'#root',
- data:{
- components:{
- school;
- hello;
- }
- }
- })
- </script>
关于VueComponent小结:
1、school组件本质是一个名为VueComponent的构造函数,且不是程序员我们自己定义的,是Vue.extend生成的;
2、我们只需要写<school></school>或者<school/>,Vue解析时就会帮我们创建一个school组件的实例对象;
3、特别注意:每次调用Vue.extend,返回的都是一个新的VueComponent。而不是使用同一个;
4、关于this只想问题:
(1)组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数、它们的this指向的均是【VueComponent实例的对象】
(2)newVue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数、它们的this指向的都是【Vue实例对象】
5、VueComponent的实例对象,简称为“VC”(组件实例对象)。Vue实例对象简称:vm
因为组件时可复用的Vue实例,所以它们与new vue接收相同的选项,例如data、computed、watch、methods以及生命周期钩子等。仅有的例外是像el这样的根实例(vm)特有的选项,一个组件的data选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立拷贝
- <body>
- <div id="root">
- <school></school> //创建组件标签
- </div>
- </body>
- <script>
- Vue.config.productionTip= false;
- Vue.prototype.x=99
- const school=Vue.extend({ //创建组件
- name:'school',
- template:`
- <div>
- <h2>学校名称{{name}}</h2>
- <h2>学校地址{{address}}</h2>
- </div>
- `,
- data(){
- return {
- name:'尚硅谷',
- address:'北京'
- }
- },
- methods:{
- showX(){
- console.log(this.x)
- }
- }
- })
- const vm = new Vue({ //创建vm实例
- el:'#root',
- data:{
- msg:'你好'
- },
- components:{school} //注册组件
- })
- </script>
VueComponent.prototype === Vue.prototype
为什么要有这个关系:让组件实例对象(vc)可以访问到Vue原型上的属性,方法(依据原型链),如果都没找到返回null。
- <template>
- <div class = "demo">
- <h2>学校名称{{name}}</h2>
- <h2>学校地址{{address}}</h2>
- <button @click="showName">点击提示学校名称</button>
- </div>
- </template>
- <script>
- export default{
- name:'school',
- data(){
- return{
- school:'尚硅谷',
- address:'北京昌平'
- }
- }.
- methods:{
- showName(){
- alert(this.schoolName)
- }
- },
- }
- <script>
- <style>
- .deom{
- background-color:pink;
- }
- </style>
- <template>
- <div>
- <h2>学生{{name}}</h2>
- <h2>年龄{{age}}</h2>
- </div>
- </template>
- <script>
- export default{
- name:'Student',
- data(){
- return{
- name:'张三',
- age:18
- }
- }
- }
- </script>
- <style></style>
二、合并组件(App)
- <template>
- <div>
- <School></School>
- <Student></Student>
- </div>
- </template>
- <script>
- //引入组件
- import School from './School'
- import Student from './Student'
- export default{
- name:'App',
- components:{
- School,
- Student
- }
- }
- </script>
三、引入合并好的组件,实例化Vue实例(main.js)
- import App from './App.Vue'
- new Vue({
- el:'#root',
- template:`<App><App>`,
- components:{
- App
- },
- })
四、创建页面(index.html)引入main.js
- <html>
- <head>
- <title>Document</title>
- </head>
- <body>
- <div id="root"></div>
- <script type='text/javascript' src='../js/vue.js'></script>
- <script type="text/javascript" src="./main.js"></script>
- </body>
- </html>
结构:
在main.js文件中:
一、引入的Vue是残缺的时,需要使用函数render:( ){ return ***}
import引入的Vue文件如果是ES6模式引入,默认指向的是vue.runtime.esm.js
- //引入Vue
- import Vue from 'vue'
- //引入App组件,它是所有组件的父组件
- //import App from './App.vue'
- Vue.config.productionTip = false;
- //创建Vue实例对象——vm
- new Vue({
- el:'#app',
- render(createElement){
- return createElement('h1','创建的是<h1></h1>标签')
- }
- ----------------------------------
- render:h =>h(App) //参数是一个组件时,直接写组件名称
- })
二、引入的Vue是完整的时:
- <body>
- <div id="root">
-
- </div>
- </body>
- <script>
- Vue.config.productionTip =false;
- new Vue({
- el:'#root',
- <template>
- <h1>你好,引入的时完整版Vue</h1>
- </template>
- })
- </script>
小结:
1、vue.js与vue.runtime.xxx.js的区别
(1)vue.js是完整版的Vue,包含:核心功能+模板解析器。
(2)vue.runtime.xxx.js是运行时的vue,只包含:核心功能;没有模板解析器。
2、因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收收到的createElement函数去指定具体内容
小结:(1)使用vue inspect >output.js可以查看Vue脚手架的默认配置
(2) 使用vue.config.js可以对脚手架进行个性化定制;
- <template>
- <h2 v-text="msg" ref="title"><>
- <button ref="btn" @click="showDOM">点击输出全部DOM元素</button>
- <School ref="sch">
- </template>
- <script>
- import School from './components/School'
- export default{
- name:'App', //组件名
- components:{School} //组件集
- data(){
- return{
- msg:'欢迎学习Vue'
- }
- },
- methods:{
- showDOM(){ //点击输出真是DOM元素,通过ref操作
- console.log(this.$refs.title)
- console.log(this.$refs.btn)
- console.log(this.$refs.sch)
- }
- }
- }
- </script>
- <style></style>
ref属性小结:
(1)被用来给元素或者子组件注册引用信息(id替代者)
(2)应用在HTML标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(VC)
(3)使用方式:
打标识方式<h1 ref="xxx"></h1> 或<School ref="xxx"></School>
获取标识:this.$refs.xxx
配置组件:
接收到的props是不允许修改,且优先使用props传递的值。
(Student.vue)
- <template>
- <div>
- <h1>{{msg}}</h1>
- <h2>学生姓名{{name}}<h2>
- <h2>学生性别{{sex}}</h2>
- <h2>学生年龄{{age}}</h2>
- <button @click="updataAge">点击年龄加加</button>
- </div>
- </template>
- <script>
- export default{
- name:'Student',
- data(){
- console.log(this)
- return {
- msg:'我是一个学生',
- //this指向的值接收过来的数据
- MyAge:this.age //修改数据,把props传递的数据复制一个放入data中
- }
- },
- methods:{
- updateAge(){
- this.myAge++
- }
- },
- props:['name','age','sex'] //简单声明接收
- ----------------------------------------
- props:{
- name:String, //接收同时对数据进行类型限制
- age:Number,
- sex:String
- }
- -------------------------------------------
- props:{ //接收同时对数据进行类型限制+默认值指定+必要性限制
- name:{
- type:String,
- required:true,
-
- },
- age:{
- type:Number,
- default:25
- }
- sex:{
- type:String
- required:true
- }
- }
- }
- </script>
收集全部组件(app.vue)
- <template>
- <div>
- <student name="张三" sex="男" :age='18+1'> //传递数据
- </div>
- </template>
- <script>
- import Student from "./components/Student"
- export default{
- name:'App',
- components:{Student}
- }
- </script>
小结:功能是让组件接收从外部传过来的数据
(1)传递数据:<Demo name="***">
(2)接收数据:
第一种方式:只接受props:['name']
第二种:限制类型props:{
name;String
}
第三种(限制类型、限制必要性、指定默认值)
props:{
name:{
type:String,
required:true,
default:'张三'
}
}
备注:props是只读的,Vue底层会检测对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么需要复制props内容中的一个数据到data中,然后去修改data中的数据
创建混合
- export const hunhe={
- methods:{
- showName(){
- alert(this.name)
- }
- },
- mounted(){ //挂载是输入你好
- console.log("你好啊")
- },
- }
- //引用混合的都会有这两个数据
- export const hunhe2={
- data(){
- return {
- x:100,
- y:200
- }
- }
- }
引入局部混合文件
注:当引入混合文件中数据和源文件数据冲突时,以源文件数据为准;都出现挂载时,全部执行。
- <template>
- <div>
- <h2 @click="showName">学校名称{{name}}</h2>
- <h2>学校地址{{address}}</h2>
- </div>
- </template>
- <script>
- //引入混合文件
- import {hunhe,hunhe2} from './mixin'
- export default{
- name:'',
- data(){
- return {
- name:'尚硅谷',
- address:'北京',
- x:666
- }
- },
- mixin:[hunhe,hunhe2],
- mounted(){
- console.log("你好!!")
- }
- }
- <script>
全局混合:
- import Vue from 'vue'
- import App from './App.vue'
- import {hunhe,hunhe2} from './mixin'
- Vue.config.productionTip = false;
- Vue.mixin(hunhe)
- Vue.mixin(hunhe2)
- new Vue({
- el:'',
- render:h=>h(App) //render使用残缺Vue时,使用
- })
mixin(混入)小结:
功能:可以吧多个组件共用的配置提取成一个混入的对象;
使用方法:第一步定义混合,例如:{ data(){***}
methods:{**}
}
第二步使用混入:
(1)全局混入:Vue.mixin(***)
(2)局部混入:mixin:[ ' *** ' ]
定义插件(plugins.js):
- export default{
- install(Vue){
- Vue.filter("mySlice",function(value){ //定义全局过滤器
- return value.slice(0,4)
- }),
- Vue.directive('fbind',{ //定义全局指定
- bind(element,binding){
- element.value=binding.value
- },
- inserted(element,binding){
- element.focus()
- },
- update(element,binding){
- element.value=binding.value
- }
- }),
- Vue.mixin({ //定义全局混入
- data(){
- return {
- x:100,
- y:100
- }
- }
- })
- 在Vue原型对象上添加一个方法(vm和VC都能用)
- Vue.prototype.hello = ()=>{alert('你好!!')}
- }
- }
应用(使用)插件(main.js):
- import Vue from 'vue'
- import App from './App.vue'
- import plugins from './plugins'
- Vue.config.productionTip= false
- Vue.use(plugins)
- new Vue({
- el:'#App',
- render h=>h(App)
- })
组件中使用插件(Student.vue):
- <template>
- <div>
- <h2>学生姓名{{name}}</h2>
- <h2>学生性别{{sex}}</h2>
- </div>
- </template>
- <script>
- export default{
- name:'Student',
- data(){
- return {
- name:'张三',
- sex:'男'
- }
- },
- }
- </script>
功能:用于增强Vue。
本质:包含install方法的对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
定义插件:
对象.install = function(Vue,options){
//添加全局过滤器
Vue.filter(***)
}
//添加全局指令
Vue.directive(***)
//配置全局混入
Vue.mixin(***)
//添加实例方法
Vue.prototype.$myMethod = function(){***}
Vue.prototype.$myProperty = ***
作用:让样式在局部生效,防止冲突。
写法:<style scoped>(style后边可以跟着lang="less"或者"css"样式,但是可能需要安装less-loader)
当两个组件样式冲突时,以引入组件的最后的那个顺序为准:
(App.vue)合并组件中
- <template>
- <div>
- <School/>
- <Student/>
- </div>
- </template>
- <script>
- import Student from './components/Student'
- import School from './components/School'
- export default{
- name:'App',
- components:{School,Student}
- }
- </script>
分组件(School.vue)
scoped:使属性仅在局部有效。
<template> <div class="demo"> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> </div> </template> <script> export default { name:'School', data(){ return{ name:'尚硅谷', address:'北京' } } } </script> <style scoped> .demo{ background-color:pink; } </style>
style后边可以跟着lang="less"或者"css"样式,但是可能需要安装less-loader:
- <template>
- <div class="demo">
- <h2>学生姓名:{{name}}</h2>
- <h2>学生年龄:{{age}}</h2>
- </div>
- </template>
- <script>
- name:'Student',
- data(){
- name:'张三',
- age:25
- }
- </script>
- <style lang=less scoped>
- .demo{
- background: blue;
- .atguigu{
- font-size:25px;
- }
- }
- </style>
Vue—— Todo-list案例
步骤一:实现静态组件:抽取组件,使用组件实现静态页面效果。
步骤二:展示动态数据:
(1)数据的类型,名称是什么。
(2)数据保存在哪个组件。
步骤三:交互——从绑定事件监听开始。·······
(MyList.vue)
<template> <ul class ="todo-main"> <MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj"/> </ul> </template> <script> import MyItem from './MyItem' export default { name:'MyList', components:{MyItem}, } </script> <style> </style>列表组件:(Myitem.vue)
<template> <li> <label> <input type="checkbox" :checked="todo.done"> <span>{{todo.title}}</span> </label> </li> </template> <script> export default{ name:'MyItem', props:['todo'], } </script> <style></style>获取添加数据(Myheader.vue)
<template> <div class ="todo-header"> <input type="text" placeholder="请输入名称,按回车确认" v-model="title" @keyup.enter='add'/> </div> </template> <script> import {nanoid} from 'nanoid' export default{ name:'MyHeader', props:["addTodo"], data(){ return{ title:'' } } methods:{ add(){ //效验数据 if(!this.title.trim()) return alert("请输入数据") 将用户的输入包装成一个todo对象 const todoObj={id:nanoid(),title:this.title,done:false} 通知App组件去添加一个todo对象 this.addTodo(todoObj) this.title='' } } } </script> <style> <style>组件集合(App.vue):
<template> <div id="root"> <div class="todo-container"> <div class="todo-wrap"> <MyHeader :addTodo="addTodo"/> <MyList :todos="todos/"> <MyFooter/> </div> </div> </div> </template> <script> import MyHeader from './components/MyHeader' import MyList from './components/MyList' import MyFooter from './components/MyFooter.vue' export default{ name:'App', components:{MyHeader,MyList,MyFooter}, data() { return{ todos:[ {id:'001',title:'吃饭',done:true}, {id:'002',title:'看书',done:false}, {id:'003',title:'打代码',done:true} ] } }, methods:{ addTodo(todoObj){ this.todos.unshift(todoObj) } }, } </script> <style></style>
一、组件化编码流程:
Window.sessionStorage大小约为5MB;
Window.localStorage大小约为20MB;
(1)、存储数据:
sessionStorage.setItem(key,value)
(2)、获取数据
sessionStorage.getItem(key,value)
(3)、删除数据
sessionStorage.removeItem(key,value)
(4)、删除所有数据
sessionStorage.clear()
学生组件
<template> <div class="student"> <h2>学生姓名:{{name}}</h2> <h2>学生性别:{{sex}}</h2> <button @click="sendStudentName">把学生名给App组件</button> </div> </template> <script> export default{ name:'Student', data(){ return{ name:'张三', sex:'男' } }, methods:{ sendStudentName(){ this.$emit("atguigu",this.name) 触发App组件实例身上的'atguigu'事件 } } } </script> <style lang="less" scoped> .demo{ background-color:'pink'; .atguigu{ font-size:40px; } } </style>学校组件:
<template> <div class="school"> <h2>学校{{name}}</h2> <h2>学校地址{{address}}</h2> <button @click="sendSchoolName">点击把学校名称给App</button> </div> </template> <script> export default{ name:'School', props:['getSchoolName'], //接收从App组件中传过来的数据 data(){ name:'尚硅谷', address:'北京' }, methods:{ sendSchoolName(){ this.getSchoolName(this.name) } } } </script> <style lang="less"> .demo{ background-color:blue; .atguigu{ font-size:40px; } } </style>App.vue组件
<template> <div class="app"> <h1>{{msg}}</h1> 通过父组件给子组件传递函数类型的props实现:子给父传递数据 <School :getSchoolName="getSchoolName"/> 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一个自定义写法:使用@或v-on) <Student v-on:atguigu="getStudentName"/> 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种自定义写法,使用ref) <Student ref="stu"/> </div> </template> <script> import Student from"./components/Student" import School from './components/School' export default{ name:'App', data(){ return{ msg:'你好啊' } }, methods:{ getSchoolNmae(name){ console.log("传递参数,学校名称",name) }, getStudentName(name){ console.log("触发了事件",name) } }, mounted(){ //挂载自定义事件 this.$refs.stu.$on("atguigu",this.getStudentName) //只执行一次 this.$refs.stu.$once("atguigu",this.getStudentName) } } </script> <style></style>
student.vue组件:
<template> <div class="student"> <h2>学生姓名:{{name}}</h2> <h2>学生性别:{{sex}}</h2> <button @click="sendStudentName">把学生名传递到App</button> <button @click="unbind">解绑指定事件</button> <button @click="xiaohui">点击销毁当前Student组件实例</button> </div> </template> <script> export default{ name:'Student', data(){ return { name:'张三', sex:'男' } }, methods:{ sendStudentName(){ this.$emit("atguigu",this.name) this.$emit("demo") } }, unbind(){ this.$off('atguigu') //解绑一个自定义事件 this.$off(['atguigu','demo']) //解绑多个自定义事件 this.$off() //解绑多个自定义事件 }, xiaohui(){ this.destroy() //销毁了当前Student组件的实例,销毁后所有的Student实例的自定义事件都失效 } } </script> <style></style>App.vue组件:
<template> <div class="app"> <h1>{{msg}}</h1> <School :getSchoolName="getSchoolName"></School> <Student @atguigu="getStudentName" @demo="m1"></Student> </div> </template> <script> import {Student} from './component/Student' import {School} from './component/School' export default{ name:'App', components:{School,Student} data(){ return{ msg:'你好啊' } }, methods:{ getSchoolName(name){ console.log("App收到了学校的名",name) }, getStudentName(name){ console.log("App收到了学生名字",name) }, m1(){ console.log("m1事件被调用了"); } }, // mounted(){ // this.$refs.student.$on('atguigu',this.getStudentName) //绑定自定义事件 // } } </script> <style></style>
一、一种组件间通信的方式,适用于:子组件===》父组件
二、使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件回调在A中);
三、绑定自定义事件:
(1)第一种方式,在父组件中:
(2)第二种方式,在父组件中:
(3)若想让自定义事件只能触发一次,可以使用"once"修饰符,或者$once方法;
四、触发自定义事件:
五、解绑自定义事件:
六、组件上可以也可以绑定原生DOM事件,需要使用“native”修饰符。
七、注意:通过绑定自定义事件时,回调要么配置在methods中,或者用箭头函数,否则this指向会出现问题。
- <template>
- <div class="app">
- <h1>{{msg}} 学生姓名是:{{studentName}}</h1>
- <Student ref="student"/>
- </div>
- </template>
- <script>
- import Student from './components/Student'
- export default {
- name:'App',
- data(){
- return {
- msg:'你好啊',
- studentName:''
- }
- },
- methods:{
- getStudentName(name){
- console.log("App收到了学生名字",name)
- this.studentName=name
- },
- m1(){
- console.log("demo事件被触发了")
- }
- },
- mounted(){
- this.$refs.student.$on('atguigu',this.getStudentName) //绑定自定义事件
- }
- }
- </script>
- <style></style>
TodoList案例自定义事件:
<template></template>
创建全局事件总线:
import Vue from 'vue' import App from './App.vue' Vue.config.productionTip=false; new Vue({ el:'', render: h=>h(App), beforeCreate(){ Vue.prototype.$bus=this //安装全局事件总线 }, })兄弟组件一传递数据:
<template> <div class="student"> <h2>学生姓名:{{name}}</h2> <h2>学生性别:{{sex}}</h2> <button @click='sendStudentName'>点击接收School组件信息</button> </div> </template> <script> export default{ name:'Student', data(){ return { name:'张三', sex:'男', } }, methods(){ sendStudentName(){ this.$bus.$emit('hello',this.name) //应用自定义事件 } } } </script> <style><style>兄弟组件——接收数据:
<template> <div class="school"> <h2>学校{{name}}</h2> <h2>学校地址{{address}}</h2> </div> </template> <script> export default{ name:'School', data(){ return{ name:'尚硅谷', address:'北京' } }, mounted() { this.$bus.$on('hello',(data)=>{ //设置自定义事件 console.log("我是School组件,Student组件收到了数据",data) }) }, beforeDestory(){ this.$bus.$off('hello') //解绑自定义事件 } } </script> <style></style>小结:
一、一种组件间通信的方式,适用于任意组件间通信。
二、安装全局事件总线:
三、使用事件总线:
(1)接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件回调留在A组件自身。
写法一:
写法二:
(2)提供数据:
四、最好在beforeDestroy钩子中,用$off解绑当前组件所用的事件。
TodoList案例——事件总线写法
(main.js)创建全局事件总线
import Vue from 'Vue' import App from './App.vue' Vue.config.productionTip=false; new Vue({ el:'#app', render:h=>(App), beforeCreate(){ Vue.prototype.$bus=this }, })App.vue创建事件,接收数据
<template></template> <script> import MyHeader from './components/MyHeader' import MyList from './components/MyList' import MyFooter from './components/MyFooter' export default { name:'App', components:{MyHeader,MyList,MyFooter} data(){}, methods:{} watch:{}, mounted(){ //挂载时,绑定全局事件总线 this.$bus.$on('checkTodo',this.checkTodo) this.$bus.$on('deleteTodo',this.deleteTodo) }, beforeDestroy() { //销毁事件时,解绑全局事件 this.$bus.$off('checkTodo') this.$bus.$off('deleteTodo') } } </script> <style></style>MyItem.vue触发事件,传递数据
<template></template> <script> export default{ name:'MyItem', props:['todo'], methods:{ handleCheck(id){ this.$bus.$emit('checkTodo',id) }, handleDelete(id){ if(confirm("确认删除吗")){ this.$bus.$emit('deleteTodo',id) } } } } </script> <style></style>
School.vue,接收数据,订阅消息
<template> <div class="school"> <h2>学校名称:{{name}}</h2> <h2>学校地址:{{address}}</h2> </div> </template> <script> import pubsub from 'pubsub-js' export default{ name:'School', data(){ return { name:'尚硅谷', address:'北京', } }, mounted(){ (消息名,数据) this pubId=pubsub.subscribe('hello',(msgName,data)=>{ console.log("有人发布了hello消息,执行会滴函数hello") }) }, beforeDestroy(){ pubsub.unsubscribe(this.pubId) } } </script> <style></style>student.vue发送数据
<template> <div>学生姓名:{{name}}</div> <div>学生性别:{{sex}}</div> <button @click="sendStudentName">把学生名发送给School组件</button> </template> <script> import pubsub from 'pubsub-js' export default{ name:'Student', data(){ return { name:'张三', sex:'男' } }, methods:{ sendStudentName(){ pubsub.publish('hello',"发送数据给School") } } } </script> <style></style>消息订阅与发布(pubsub)
小结:
1、安装pubsub:
2、引入pubsub:
3、接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件中
写法二:
4、提供数据:
5、最好在beforeDestroy钩子中,用
TodoList案例优化——消息订阅方式
App.vue
import MyList from './components/MyList' import MyFooter from './components/Footer' export default{ name:'App', components:{MyHeader,MyList,MyFooter}, data(){}, methods:{}, watch:{}, mounted(){ this.$bus.$on('checkTodo',this.checkTodo) this.pubId=pubsub.subscribe('deleteTodo',this.deleteTodo) }, beforeDestroy(){ this.$bus.$off('checkTodo') pubsub.unsubscribe(this.pubId) } }MyItem.vue
import pubsub from 'pubsub-js' export default{ name:'MyItem', props:['todo'], methods:{ handleCheck(id){ this.$bus.$emit('checkTodo',id) } }, handleDelete(id){ if(confirm('确定删除吗')){ pubsub.publish('deleteTodo',id) } } }
TodoList案例优化——添加编辑功能
MyItem.vue
<template> <li> <label> <input type='checkbox' :checked="todo.done" @change="handleCheck(todo.id)"> <span v-show="!todo.isEdit">{{todo.title}}</span> <input type="text" v-show="todo.isEdit" :value="todo.title" @blur="handleBlur(todo)"> </label> <button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button> <button v-show="!todo.isEdit" class="btn btn-edit" @click="handleEdit(todo)">编辑</button> </li> </template> <script> import pubsub from "pubsub-js" export default{ name:'MyItem', props:['todo'], methods:{ handleCheck(id){}, handleDelete(id){}, handleEdit(todo,$event){ if(todo.hasOwnProperty('isEdit')){ todo.isEdit =true } else{ this.$set(todo,'isEdit',true) } }, //失去焦点回调,(真正执行修改逻辑) handleBlur(todo,e){ todo.isEdit=false if(!e.target.value.trim()) return("输入不能为空") this.$bus.$emit('updataTodo',todo.id,e.target.value) } } } </script> <style></style>App.vue文件中
<template></template> <script> import MyHeader from './components/MyHeader' import MyList from './components/MyList' import MyFooter from './components/MyFooter' export default{ name:'App', components:{MyHeader,MyList,MyFooter} data(){}, methods:{ addTodo(todoObj){}, checkTodo(id){ this.todos.forEach((todo)=>{ if(todo.id=id) todo.done=!todo.done }) }, updataTodo(id,title){ this.todos.forEach((todo)=>{ if(todo.id=id) todo.title=title }) }, deleteTodo(_,id)}{}, checkAllTodo(done){}, clearAllTodo(){} }, mounted(){ this.$bus.$on('checkTodo',this.checkTodo) this.$bus.$on('updataTodo',this.updataTodo) this.pubId=pubsub.subscribe('deleteTodo',this.deleteTodo) }, beforeDestroy(){ this.$bus.$off('checkTodo') this.$bus.$off('updataTodo') pubsub.unsubscribe(this.pubId) } } </script> <style></style>
MyItem.vue
点击自动获取焦点:
<template> <li> <label> <input type='checkbox' :checked="todo.done" @change="handleCheck(todo.id)"> <span v-show="!todo.isEdit">{{todo.title}}</span> <input type="text" v-show="todo.isEdit" :value="todo.title" ref="inputTitle" @blur="handleBlur(todo)"> </label> <button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button> <button v-show="!todo.isEdit" class="btn btn-edit" @click="handleEdit(todo)">编辑</button> </li> </template> <script> import pubsub from "pubsub-js" export default{ name:'MyItem', props:['todo'], methods:{ handleCheck(id){}, handleDelete(id){}, handleEdit(todo,$event){ if(todo.hasOwnProperty('isEdit')){ todo.isEdit =true } else{ this.$set(todo,'isEdit',true) }, 方式一:--------------------------------------------- this.$nextTick(function(){ this.$refs.$inputTitle.focus() }) 方式二:---------------------------------------------- setTimeout({ this.$refs.$inputTitle.focus() },10) }, //失去焦点回调,(真正执行修改逻辑) handleBlur(todo,e){ todo.isEdit=false if(!e.target.value.trim()) return("输入不能为空") this.$bus.$emit('updataTodo',todo.id,e.target.value) this.$refs.inputTitle.focus() } } } </script> <style></style>nextTick小结:
(1)、语法:this.%nextTick(“回调函数”)
(2)、作用:在下一次DOM更新结束后,执行其指定的回调;
(3)、什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
子组件:
<template> <div> <button @click="isShow = !isShow">显示/隐藏</button> <transition appear> //如果transition有名称,则,调用时需要加上名,加上appear可以出现进入动画 <h1 v-show="isShow">你好啊</h1> </transition> </div> </template> <script> export default{ name:'Test', data(){ return{ isShow:true } } } </script> <style scoped> h1{ background-color:pink; } .v-enter-active{ animation:donghua 1s linear; } .v-leave-active{ animation:donghua 1s linear reverse; } @keyframes donghua{ from{ transfrom:translateX(-100px); } to{ transfrom:translateX(0px) } } </style>父组件:
<template> <div> <Text/> </div> </template> <script> import Test from './conponents/Test' export default{ name:'App', components:{Test} } </script> <style> </style>过渡效果
子组件:
<template> <div> <button @click="isShow = !isShow>显示隐藏</button> <transition name="hello" appear> <h2 v-show="isShow"></h2> </transition> </div> </template> <script> export default{ name:'Test2', data(){ return{ isShow=true; } } } </script> <style> h2{ background-color:pink; transition:1s linear; } //进入的起点;离开的终点 .hello-enter,.hello-leave-to{ transform:translateX(-100px); } //进入的过程中,离开的过程中 .hello-enter-active,.hello-leave-active{ transition:1s linear; } //进入的终点;离开的起点 .hello-enter-to,.hello-leave{ transform:translateX(0px); } </style>父组件:
<template> <div> <Test/> <Test2/> </div> </template> <script> import Test from './components/Test' import Test2 from './components/Test2' export default{ name:'App', components:{ Test, Test2 } } </script> <style></style>多个元素过渡:
利用<transition-group></transition-group>
集成第三方库,创建动画:
- <template>
- <ul>
- <transition-group name="todo" appear>
- <MyItem>
- v-for="todoObj in todos"
- :key="todoObj.id"
- :todo="todoObj"
- </MyItem>
- </transition-group>
- </ul>
- </template>
- <script>
- import MyItem from './MyItem'
- export default{
- name:'MyList',
- components:{MyItem},
- props:['todos']
- }
- </script>
- <style>
- .todo-enter-active{
- animation:donghua 1s linear;
- }
- .todo-leave-active{
- animation:donghua 1s linear reverse;
- }
- @keyframes donghua{
- from{
- transfrom:translateX(-100px);
- }
- to{
- transfrom:translateX(0px)
- }
- }
- </style>
Vue封装过渡与动画:
1、作用:在插入、更新或移除DOM元素时,在合适的时候给元素添加样式类名。
2、如图:
写法:
(1)准备好样式:
元素进入的样式:1、v-enter:进入的起点
2、v-enter-active:进入的过程中
3、v-enter-to:进入终点
元素离开样式:
1、v-leave:离开的起点;
2、v-leave-active:离开过程中
3、v-leave-to:离开的终点
3、使用<transition>包裹要过渡的元素,并配置name属性:
- <transition>
- <h1 v-show="isShow">你好啊</h1>
- </transition>
配置代理——方式一
在脚手架中,创建代理服务器:
module.exports={ pages:{ index:{ entry:'src/main.js' }, }, lintOnSave:false, 开启代理服务器 devServer:{ proxy:'http://localhost:5000' } }这样配置代理方式两点不足:(1)一次只能配置一个搭理服务器;
(2)如果在本文件中有和请求同名字的,则执行本文件中的,不执行服务器中的;
App.vue组件
<template> <div> <button @click="getStudents">获取学生信息</button> </div> </template> <script> import axios from 'axios' export default{ name:'App', methods:{ getStudents(){ axios.get('https://localhost:8080/student').then( response=>{ console.log('请求成功',response.data) } error=>{ console.log("请求失败",error.message) } ) } } } </script>方式一小结:
在脚手架文件中(vue.config.js)添加如下配置:
优点:配置简单,请求资源时直接发给前端(8080)即可。
缺点:不能配置多个代理,不能灵活控制请求是否走代理。
工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器(优先匹配前端资源)
配置代理方式二:
Vue.config.js在脚手架中,配置
module.exports={ pages:{ index:{ entry:'src/main.js', }, }, lintOnSave:false, devServer:{ proxy:{ '/atguigu':{ target:'http://localhost:5000', pathRewrite:{'^/atguigu':''} ws:true, //用于支持websocket changeOrigin:true //是否传递真实服务器端口 }, '/demo':{ target:'http://localhost:5001', pathRewrite:{'^/demo':''} } } } }(changeOrigin:true / false:用于控制请求头中的host值)
同时配置多个代理服务器:
<template> <div> <button @click="getCars">点击获取汽车信息</button> <button @click="getStudents">获取学生信息</button> </div> </template> <script> import axios from 'axios' export default { name:'App', methods:{ getStudents(){ axios.get('http://localhost:8080/atguigu/students').then( response=>{ console.log("请求成功",response.data) }, error=>{ console.log("请求失败",error.message) } ) }, getCars(){ axios.get("http://localhost:8080/demo/car").then( response=>{ console.log('',response.data) }, error=>{ console.log("请求失败了",error.message) } ) } } } </script> <style></style>方式二小结:
html引入第三方库
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="icon" href="<%=BASE_URL %>favicon.ico"> <link rel="stylesheet" href="<%= BASE_URL %> css/bootstarp.css"> <title><%=htmlWebpackPlugin.options.title %></title> </head> <body> <noscript> <strong>当浏览器不支持js时执行</strong> </noscript> <div id="app"></div> </body> </html>App组件
<template> <div class='container'> <Search/> <List/> </div> </template> <script> import Search from './components/Search.vue' import List from './components/List.vue' export default{ name:'App', components:{Search,List} } <script> <style></style>子组件:Search.vue
<template> <section class="jumbotron"> <h3 class="jumbotron-heading"></h3> <div> <input type="text" placeholder="enter the name you search" v-model="keywords"/> $nbsp; <button @click="searchUsers">search</button> </div> </section> </template> <script> export default{ name:'Search', data(){ return{ keyWord:'' } }, methods:{ searchUsers(){ this.$bus.$emit('userList',{isFirst:false,isLoading:true,errMsg:'',users:[]}) axios.get(`https://api.github.com/search/users?q=${this.keyWord}`).then( response=>{ console.log("请求成功") this.$bus.$emit("userList",{isLoading:false,errMsg:'',users:response.data.item}) }, error=>{ console.log("请求失败",isLoading:false,errMsg:error.message,user:[]) } ) }, }, } </script> <style></style>子组件:List.vue
<template> <div class="row"> <div class="card" v-for="user in users" :key="user.login"> <a :href="user.html_url" target="_blank"> <img :src="user.avatar_url" style="width:100px"> </a> <p class="card-text">{{user.login}}</p> </div> <h1 v-show="isFirst">欢迎使用</h1> <h1 v-show="isLoading">加载中</h1> <h1 v-show="errMas">{{errMas}}</h1> </div> </template> <script> export default{ name:'List', data(){ return { info:{ isFirst:true, isLoading:false, errMas:'', users:[] } } }, mounted(){ (形参) this.$bus.$on("userList",(dataObj)=>{ this.info={...this.info,...dataObj} (上边的info中的参数) console.log(this) }) },- } </script> <style> </style>
main.js
import Vue from 'vue' import App from './App.vue' import vueResource from 'vue-resource' Vue.config.productionTip=false Vue.use(vueResource) new Vue({ el:'', render:h=>h(App), beforeCreate(){ Vue.prototype.$bus=this }, })Search.vue
<template> <section class="jumbotron"> <h3 class="jumbotron-heading"></h3> <div> <input type="text" placeholder="enter the name you search" v-model="keywords"/> $nbsp; <button @click="searchUsers">search</button> </div> </section> </template> <script> import axios from 'axios' export default{ name:'Search', data(){ return{ keyWord:'' } }, methods:{ searchUsers(){ this.$bus.$emit('userList',{isFirst:false,isLoading:true,errMsg:'',users:[]}) this.$http.get(`https://api.github.com/search/users?q=${this.keyWord}`).then( response=>{ console.log("请求成功") this.$bus.$emit("userList",{isLoading:false,errMsg:'',users:response.data.item}) }, error=>{ console.log("请求失败",isLoading:false,errMsg:error.message,user:[]) } ) }, }, } </script> <style></style>
子组件category.vue
<tmeplate> <div class="category"> <h3>{{title}}</h3> <slot></slot> //定义一个插槽;等组件使用者向里边填充 </div> </template> <script> export default{ name:'Category', props:['title'] } </script> <style></style>App.vue父组件
<template> <div class="container"> <Category title="实物"> <img src="https://*****.jpg" alt=""> </Category> <Category title="游戏""> <ul> <li v-for="(item,index) in games" :key="index">{{item}}</li> </ul> </Category> </div> </template> <script> import Category from './components/Category' export default{ name:'App', components:{Category} data(){ return{ foots:['牛肉','羊肉',], games:['打代码','看书'] } } } </script> <style></style>
Vue——具名插槽
<template> <div class="container"> <Category title="实物"> <img slot="center" src="https://*****.jpg" alt=""> <a slot="foot" href="http://www.***.com">更多美食</a> </Category> <Category title="游戏"> <ul slot="center"> <li v-for="(item,index) in listData" :key="index">{{item}}</li> </ul> <template v-slot:foot> //最新写法,但是只能放在template标签中 <div class="foot"> <a href="http://***">单机游戏</a> <a href="http://***">网络游戏</a> </div> <h2>使用template可以包裹放入同一个组件中</h2> </template> </Category> </div> </template> <script> import Category from './components/Category' export default{ name:'App', components:{Category} data(){ return{ foots:['牛肉','羊肉',], games:['打代码','看书'] } } } </script> <style></style>Category.vue组件
<tmeplate> <div class="category"> <h3>{{title}}</h3> <slot name="center"></slot> //定义一个具有名字插槽;等组件使用者向里边填充 <slot name="foot"></slot> //定义一个具有名字插槽;等组件使用者向里边填充 </div> </template> <script> export default{ name:'Category', props:['title'] } </script> <style></style
Vue—— 作用域插槽,
App.vue组件:
<template> <div class="container"> <Category title="美食"> <template scope="atguigu"> <ul> <li v-for="(g,index) in atguigu.game":key="index">{{g}}</li> </ul> </template> </Category> <Category title="游戏"> <template scope="{games}"> <ol> <li v-for="(g,index) in games":key="index">{{g}}</li> </ol> </template> </Category> </div> </template> <script> import Category from './components/Category' export default{ name:'App', components:{Category}, } </script> <style></style>Category.vue组件
<template> <div class="category"> <h3>{{title}}</h3> <slot :games="games" msg="hello">默认的内容,如果没有传递过来插槽则显示</slot> </div> </template> <script> export default{ name:'Category', props:['title'] data(){ return { game:['红警','原神','打代码'] } } } </script> <style></style>插槽小结:
一、作用:让父组件可以向子组件指定位置插入html结构,也是一种组件通信方式,适用于父组件===》子组件。
二、分类:默认插槽、具名插槽、作用域插槽。
三、使用方式:
1、默认插槽:
2、具名插槽:
3、作用域插槽:
一、概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue中应用多个组件的共享状态进行集中式的管理(读写),也是一种组件间通信的方式,且适用于任意组件间通信、
二、GitHub地址:
什么时候使用Vuex :(1)多个组件依赖于统一状态;(2)来自不同组件的行为需要变更同一状态
- <template>
- <div>
- <h1>当前和是{{sum}}</h1>
- <select v-model="n">
- <option :value="1">1</option>
- <option :value="2">2</option>
- <option :value="3">3</option>
- </select>
- <button @click="increment">+</button>
- <button @click="decrement">-</button>
- <button @click="incrementOdd">当前求和为奇数再加一</button>
- <button @click="incrementWait">等一等再加</button>
- </div>
- </template>
- <script>
- export default{
- name:'Count',
- data(){
- return{
- n:1,
- sum:0
- }
- },
- methods:{
- increment(){
- this.sum+=this.n;
- },
- decrement(){
- this.sum-=this.n;
- },
- incrementOdd(){
- if(this.sum % 2){
- this.sum+=this.n;
- }
- },
- incrementWait(){
- setTimeout({
- this.sum+=this.n;
- },1000)
- },
- }
- }
- </script>
- <sty></style>
分析Vuex的原理
步骤:
index.js
//引入Vue核心库 import Vue from 'vue' //引入Vuex import Vuex from 'vues' //应用Vuex插件 Vue.use(Vuex) //准备actions对象——响应组件中用户的动作 const actions={} //准备mutations对象修改state中的数据 const mutations={} //准备state对象——保存具体的数据 const state={} //创建并暴露store export default new Vuex.Store({ actions, mutations, state })main.js中创建vm时传入store配置项
import Vue from 'vue' import App from './App.vue' import vueResource from 'vue-resource' //引入store import store from './store' Vue.config.producation=flase Vue.use(vueResource) //创建vm new Vue({ el:'#app', render:h=>h(App), store, beforeCreate(){ Vue.prototype.$bus = this } })
Count.vue组件
<template> <div> <h1>当前求和为:{{$store.state.sum}}</h1> <select v-model.number='n'> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button @click="increment">+</button> <button @click="decrement">-</button> <button @click="incrementOdd">当前求和为奇数再加</button> <button @click="incrementWait">等一等再加</button> </div> </template> <script> export default{ name:'Count', data(){ return { n:1 } }, methods:{ increment(){ this.$store.commit('jia',this.n) //不用经过处理的数据,直接跳过action }, decrement(){ this.$store.commit('jian',this.n) //不用经过处理的数据,直接跳过action }, incrementOdd(){ this.$store.dispatch('jiaOdd',this.n) }, incrementWait(){ this.$store.dispatch('jiaWait',this.n) }, }, mounted(){ } } </script> <style></style>index.js:
import Vue from 'vue' import Vuex from 'vues' Vue.use(Vuex) const actions = { //准备action——用于响应组件中的动作 jia(context,value){ //函数的简写:jia:function(){} ; context译为上下文 console.log('actions中的jia被调用了') context.commit('JIA',value) }, jian(context,value){ console.log('actions中的jian被调用了') context.commit('JIAN',value) }, jiaOdd(context,value){ console.log('actions中的jiaOdd被调用了') if(context.state.sum % 2){ context.commit('JIA',value) } }, jiaWait(context,value){ console.log("actions中的jiaOdd被调用了") setTimeout(()=>{ context.commit('JIA',value) },1000) } }, const mutations={ JIA(state,value){ console.log('mutations中的JIA被调用了') state.sum+=value }, JIAN(state,value){ console.log('mutations中的JIA被调用了') state.sum-=value }, }, //初始化数据 const state={ sum:0 }, //创建并暴露store export default new Vues.Store({ actions, mutations, state, })小结:
(1)组件中读取Vuex中的数据:
(2)组件中修改vuex中的数据:
备注:
Vue——getters配置项
一、概念:当state中的数据需要经过加工后再使用时,可以使用getters加工;
index.js文件中
import Vue from 'vue' import Vuex from 'vues' Vue.use(Vuex) ................ const actions={} const mutations={} const state={ sum=0 } ...... const getters={ bigSum(state){ return state.sum*10 } } export default new Vuex.Store({ actions, mutations, state, getters })Count.vue组件中
<template> <div> <h1>当前值和为:{{$store.state.sum}}</h1> <h3>当前求和放大十倍为:{{$store.getters.bigSum}}</h3> ....... </div> </template> <script> export default{ name:'Count', ....... methods:{ increment(){ this.$store.commit('jia',this.n) //不用经过处理的数据,直接跳过action }, decrement(){ this.$store.commit('jian',this.n) //不用经过处理的数据,直接跳过action }, incrementOdd(){ this.$store.dispatch('jiaOdd',this.n) }, incrementWait(){ this.$store.dispatch('jiaWait',this.n) }, }, mounted(){ console.log('Count',this.$store) } } </script> <style></style>
"...":es6把...后边的展开。
<template> <div> <h1>当前值和为:{{$store.state.sum}}</h1> <h3>当前求和放大十倍为:{{$store.getters.bigSum}}</h3> ....... </div> </template> <script> import {mapState,mapGetters} from "vues" export default{ name:'Count', data(){}, computed:{ 靠程序员自己写计算属性 sum(){ return this.$store.state.sum }, school(){ return this.$store.state.school }, subject(){ return this.$store.state.subject }, -------------------------------- 借助mapState生成计算器,从state中读取数据:对象写法 ...mapState({sum:'sum',school:'school',subject:'subject'}) 数组写法,当属性名和计算时名相同时 ...masState(['sum','school','subject']) 借助mapGetters生成计算器,从getters中读取属性:对象写法 ...mapGetter({bigSum:'bigSum'}) 数组写法,当属性名和计算时名相同时 ...mapGetter(['bigSum']) }, methods:{} } </script> <style></style>小结:
Count.vue组件:
mapMutations生成对应方法:
<template> <div> <h1>当前值和为:{{$store.state.sum}}</h1> <h3>当前求和放大十倍为:{{$store.getters.bigSum}}</h3> ....... <button @click="increment(n)">+</button> <button @click="decrement(n)">-</button> <button @click="incrementOdd(n)">当前求和为奇数再加</button> <button @click="incrementWait(n)">等一等再加</button> </div> </template> <script> import {mapMutations} from "vues" export default{ name:'Count', data(){}, computed:{} methods:{ //靠程序员自己写计算属性 increment(){ this.$store.commit('JIA',this.n) }, decrement(){ this.$store.commit('JIAN',this.n) } ------------------------------- //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations:对象写法 ...mapMutations({increment:'JIA',decrement:'JIAN'}), //借助mapMutations生成对应的方法,方法会调用commit去联系mutations:数组写法 ...mapMutations({'JIA','JIAN'}) } } </script> <style></style>mapActions生成对应方法:
<template> <div> <h1>当前值和为:{{$store.state.sum}}</h1> <h3>当前求和放大十倍为:{{$store.getters.bigSum}}</h3> ....... <button @click="increment(n)">+</button> <button @click="decrement(n)">-</button> <button @click="incrementOdd(n)">当前求和为奇数再加</button> <button @click="incrementWait(n)">等一等再加</button> </div> </template> <script> import {mapActions} from "vues" export default{ name:'Count', data(){}, computed:{} methods:{ //靠程序员自己写计算属性 increment(){ this.$store.dispatch('JIA',this.n) }, decrement(){ this.$store.dispatch('JIAN',this.n) } ------------------------------- //借助mapMutations生成对应的方法,方法中会调用dispatch去联系actions:对象写法 ...mapActions({increment:'JIA',decrement:'JIAN'}), //借助mapMutations生成对应的方法,方法会调用dispatch去联系actions:数组写法 ...mapActions({'JIA','JIAN'}) } } </script> <style></style>小结:
注意:使用
如果需要传递参数,在模板中绑定事件时,就需要传递阐参数,否则参数是默认事件对象(单击,鼠标移动...)
person.vue
<template> <h2>人员列表组件</h2> <h3>Count组件的和为:{{sum}}</h3> <div> <input type = 'text' placeholder="请输入姓名" v-model="name"> <button @click="add">添加</button> <ul> <li v-for"p in personList" :key="p.id">{p.name}</li> </ul> </div> </template> <script> import {nanoid} from 'nanoid' export default{ name:'Person', computed:{ personList(){ //程序员自己写代码,计算属性 return this.$store.state.personList }, sum(){ return this.$store.state.sum } }, data(){ return{ name:'' } }, methods:{ add(){ const personOjb = {id:nanoid(),name:this.name} this.$store.commit('ADD_PERSon',personObj) this.name="" } } } ------------------------------------- import {mapState} from 'vuex' export default{ name:'Person', computed:{ //通过引入vuex的mapState计算属性 ...mapState(['personList']) 数组方式 } } </script> <style></style>Count.vue组件
<template> <div> <h1>当前求和为:{{$store.state.sum}}</h1> <h3>当前值放大十倍是:{{bigSum}}</h3> <h3>我在{{school}},学习{{subject}}</h3> <h3>person组件的总人数是:{{personList.length}}</h3> <select v-model.number='n'> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button @click="increment">+</button> <button @click="decrement">-</button> <button @click="incrementOdd">当前求和为奇数再加</button> <button @click="incrementWait">等一等再加</button> </div> </template> <script> import {mapState,mapGetters,mapMutations,mapActions} from 'vuex' export default{ name:'Count', data(){ return{ n:1, } }, computed:{ ...mapState(['sum','school','subject','personList']), ...mapGetters(['bigSum']) } methods{ ...mapMutations({increment:'JIA',decrement:'JIAN'}), ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'}) } } </script> <style></style>index.js中配置数据
import Vue from 'vue' import Vuex from 'vux' Vue.use(Vuex) const actions={} const mutations={ ...... ADD_PERSON(state,personObj){ console.log('mutations中的ADD_PERSON被调用了') state.personList.unshift() } } const state={ sum:0, school:'尚硅谷', subject:'前端', personList:[ {id:'001',name:'张三'} ] } const getters={} export default{ actions, mutations, state, getters }
小结:
一、定义:是vue的一个插件库,专门用来实现SPA应用。
二、对SPA应用的理解:
1、单页Web应用(SPA)
2、整个应用只有一个完整的页面(index.html)
3、点击页面中的导航链接不会刷新页面,只会做页面的据不更新。
4、数据需要通过Ajax获取。
三、路由的理解
1、什么是路由?
(1)一个路由就是一组映射关系(key-value)
(2)key为路径,value可能是function或者component
2、路由分类:
(1)后端路由:
理解:value是function,用于处理客户端提交的请求。
工作过程:服务器接收到一个请求时,根据请求路径找到匹配的函数来处理请求,返回相应数据。
(2)前端路由:
理解:value是component,用于展示页面内容。
工作过程:当浏览器的路径改变时,对应的组件就会显示。
Home.vue组件
<template> <h2>我是HOME内容</h2> </template> <script> export default{ name:'Home' } </script>About.vue组件
<template> <h2>我是ABOUT内容</h2> </template> <script> export default{ name:'About' } </script>App.vue组件
<template> <div> ....... <div class='row'> <div class=""> <div class="list-group"> 原始的html中我们使用a标签实现页面的跳转 <a class="list-group-item active" href="./about.html">About</a> <a class="list-group-item" href="./home.html">Home</a> ----------------------------------------------- // Vue中借助router-link实现组件切换 <router-link class="list-group-item" active-class="active" to="/about">About</router-link> <router-link class="list-group-item" active-class="active" to="/home">Home</router-link> </div> </div> <div class="clo-xs-6"> <div class="pannel"> <div class="pannel-body"> <router-view></router-view> //路由器视图,指定组件呈现位置 </div> </div> </div> </div> </div> </template> <><>main.js
import Vue from 'vue' import App from './App.vue' 引入VueRouter路由器 import VueRounter from 'vue-router' 引入路由器 import router from './router/index' //index文件可以省略 Vue.config.productionTip=false; Vue.use(VueRouter) new Vue({ el:'#app', render:h=>h(App), router:router })router文件夹中创建index.js,这个文件夹专门用来创建整个应用的路由器:
引入VueRouter import VueRounter from 'vue-router' 引入路由组件 import About from './components/About' import Home From './components/Home' //创建并暴露一个人路由器 export default router = new VueRouter({ routes:[ //路由器里边的路由 { path:'/about', component:About }, { path:'/home', component:Home } ] })小结:
1、安装vue-router,命令:npm i vue-router
2、应用插件:
3、编写router配置项:
路由中分为:路由组件、一般组件
根据使用方式区分:利用路由器来调用的组件为路由组件;通过我们自己用组件标签调用的为一般组件。
小结
1、路由组件通常存放在pages文件夹,一般组件通常存放在components文件夹。
2、通过切换,“隐藏了”的路由组件,默认是贝销毁的,需要使用时候再挂载。
3、每个组件都有自己的$route属性,里面存储着自己的路由信息。
4、整个应用只有一个$router,可以通过组件的$router属性获取到。
Home组件
<template> <h2>Home组件内容</h2> <div> <ul class="nav nav-tabs"> <li> <router-link class="list-group-item"active-class="active" to="/home/news">News</a> </li> <li> <router-link class="list-group-item"active-class="active" to="/home/message">Message</a> </li> </ul> </div> </template> <script> </script> <style></style>message.vue组件
<template> <div> <ul class="nav nav-tabs"> <li> <a href="/message1">message001</a> $nbsp;$nbsp; </li> <li> <a href="/message2">message002</a> $nbsp;$nbsp; </li> <li> <a href="/message3">message002</a> $nbsp;$nbsp; </li> </ul> </div> </template> <script> export default{ name:'Message' } </script> <style></style>news.vue组件
<template> <ul> <li>new001</li> <li>new002</li> <li>new003</li> </ul> <template> <script> export default{ name:'News', } </script> <style></style>index.js创建路由规则
import About from '../pages/About' import Home from '../pages/Home' import News from '../pages/News' export default new VueRouter({ routes:[ { path:'/about', component:About }, { path:'/home', component:Home, children:[ { path:'news', component:News, } ] } ] })小结:
1、多级路由规则,使用children配置项:
2、跳转(要写完整路径)
Detail.vue组件
<template> <ul> <li>消息编号:{{$route.query.id}}</li> <li>消息标题{{$route.query.title}}</li> </ul> </template> <script> export default{ name:'Detail', mounted(){ console.log(this.$route) } } </script>message.vue组件
<template> <div> <ul> <li v-for="m in messageList" :key="m.id"> //跳转路由并携带query参数,to的字符串写法: <router-link :to="`home/message/detail?id=${m,id}&title=${m.title}`"></router-link>   //跳转路由并携带query参数,to的对象写法 <router-link :to="{ path:'/home/message/detail', query:{ id:m.id, title:m.title } }">{{m.title}}</router-link> </li> </ul> <router-view></router-view> </div> </template> <script> export default{ return{ messageList:[ {id:'001',title:'消息一'}, {id:'002',title:'消息二'}, {id:'003',title:'消息三'}, ] } } </script> <style></style>配置index.js路由规则
import About from '../pages/About' import Home from '../pages/Home' import News from '../pages/News' import Detail from '../pages/Detail' export default new VueRouter({ routes:[ { path:'/about', component:About }, { path:'/home', component:Home, children:[ { path:'news', component:News, children:[ path:'detail', component:Detail ] } ] } ] })小结:
Vue——命名+-路由
作用:可以简化路由的跳转。
如何使用
1、给路由命名:
2、简化跳转:
1、配置路由,声明接收params参数
2、传递参数
注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!
3、接收参数
router文件夹中index.js配置规则
import About from '../pages/About' import Home from '../pages/Home' import News from '../pages/News' import Detail from '../pages/Detail' export default new VueRouter({ routes:[ { path:'/about', component:About }, { path:'/home', component:Home, children:[ { path:'news', component:News, children:[ name:"命名路由", path:'detail/:id/:title', component:Detail, ---------------------------------------- props的第一种写法,值为对象, 该对象中的所有的key-value都会以props的形式传给Detail组件(只能传递固定值) props:{a:1,b:'zujian'} ----------------------------------- props第二种写法,值为布尔值, 如果为真,就会把该路由组件中收到的所有params参数,以props的形式传给Detail组件。 props:true ] } --------------------------------------- props第三种写法,值为函数, props($route){ return { id:$route.query.id, title:$route.query.title } } ] } ] })Detail.vue组件中
<template> <ul> <li>消息编号:{{id}}</li> <li>消息标题:{{title}}</li> <li>{{a}}</li> <li>{{b}}</li> </ul> </template> <script> export default{ name:'Detail', -------------------------------第一种写法 props:['a','b'] computed:{ id(){ return this.$route.params.id }, title(){ return this.$route.params.title }, }, ---------------------------第二种写法 props:['id','title'] --------------------------------第三种写法 props:['id','title'] } </script> <style></style>小结:
小结:
messageList组件
<template> <div> <ul> <li v-for="m in messageList" :key="m.id"> <router-link :to="{ name:'', query:{ id:m.id, title:m.title } }">{{m.title}}</router-link> <button @click='pushShow(m)'>push查看</button> <button @click='replaceShow(m)'>replace查看</button> </li> </ul> </div> </template> <script> export default{ name:'Message', data(){ }, methods:{ pushShow(){ //记录每次跳转的记录,回退逐个回退 this.$router.push({ name:'xiangqing', query:{ id:m.id, title:m.title } }) }, replaceShow(m){ //销毁上一次的记录, this.$router.replace({ name:'xiangqing', query:{ id:m.id, title:m.title } }) } } } </script> <style> </style>
<template> <div class="col-xs-offset-2"> <div class="page-header"> <button @click="back">后退</button> <button @click="forward">前进</button> <button @click="go">根据数字正值前进,负值后退</button> </div> </div> </template> <script> export default{ name:'Banner', methods:{ back(){ this.$router.back() } forward(){ this.$router.forward() } go(){ this.$router.go(2) //前进两步记录 } } } </script> <style></style>
<template> <div> <h2>Home组件内容</h2> <div> <ul> <li> <router-link class="list-group-item" active-class="active" to="/home/news">News</router-link> </li> <li> <router-link class="list-group-item" active-class="active" to="/home/Message">Message</router-link> </li> </ul> <keep-alive include="News"> 指定缓存的组件名 <router-view></router-view> </keep-alive> </div> </div> </template> <script> export default{ name:'Home' } </script> <style></style>小结:
当需要保持多个缓存组件时,可以在通过绑定include数组:
1、作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
2、具体名字:
(1)activated路由组件被激活时触发
(2)deactivated路由组件失活时触发
<template> <ul> <li :style="{opacity}">透明度变化动画</li> <li>new001</li> <li>new002</li> <li>new003</li> </ul> <template> <script> export default{ name:'News', data(){ return{ opacity:1 } }, activated(){ console.log("News组件被激活了") this.timer = setInterval(()=>{ this.opacity-=0.01 if(this.opacity <= 0) this.opacity=1 },100) }, deactivated(){ console.log("News组件失活了") clearInterval(this.timer) } } </script> <style></style>
路由规则index.js文件
import About from '../pages/About' import Home from '../pages/Home' import News from '../pages/News' import Detail from '../pages/Detail' export default new VueRouter({ routes:[ { path:'/about', component:About }, { path:'/home', component:Home, children:[ { path:'news', component:News, children:[ path:'detail', component:Detail props($route){ return { id:$route.query.id, title:$route.query.title } ] } ] } ] }) router.deforeEach((to,from,next)=>{ //全局前置路由守卫 ——初始化的时候被调用,每次路由切换之前被调用 //to:前往的地址; //from:来自的地址; //next:是否允许放行 if(to.path==='/home/news' || to.path==='/homemessage'){ if(localStorage.getItem('school')==='atguigu'){ next() }else{ alert("学校名称不对,无权限") } }else{ next() } })全局后置——路由守卫
import About from '../pages/About' import Home from '../pages/Home' import News from '../pages/News' import Detail from '../pages/Detail' export default new VueRouter({ routes:[ { path:'/about', component:About, meta:{title:'关于'} }, { path:'/home', component:Home, meta:{title:'标题'} children:[ { path:'news', component:News, meta:{isAuth:true} children:[ path:'detail', component:Detail props($route){ return { id:$route.query.id, title:$route.query.title } ] } ] } ] }) router.deforeEach((to,from,next)=>{ 全局前置路由守卫 ——初始化的时候被调用,每次路由切换之前被调用 //to:前往的地址; //from:来自的地址; //next:是否允许放行 if(to.meta.isAuth){ //判断是否需要鉴权 if(localStorage.getItem('school')==='atguigu'){ next() }else{ alert("学校名称不对,无权限") } }else{ next() } }) 全局后置路由守卫 ——初始化的时候被调用,每次路由切换之后被调用 router.afterEach((to,from)=>{ console.log("后置路由守卫") if(to.meta.title){ document.title=to.meta.title //修改网页的title }else{ document.title="默认标题" } })Vue——独享路由守卫
import About from '../pages/About' import Home from '../pages/Home' import News from '../pages/News' import Detail from '../pages/Detail' export default new VueRouter({ routes:[ { path:'/about', component:About, meta:{title:'关于'} }, { path:'/home', component:Home, meta:{title:'标题'} children:[ { path:'news', component:News, meta:{isAuth:true,} beforeEnter:()=>{ 独享守卫 console.log("独享守卫",to,from) if(to.meta.isAuth){ if(localStorage.getItem('school')==='atguigu'){ next() }else{ alert("学校名不对,无权限") } }else{ next } } children:[ path:'detail', component:Detail props($route){ return { id:$route.query.id, title:$route.query.title } ] } ] } ] }) 全局后置路由守卫 ——初始化的时候被调用,每次路由切换之后被调用 router.afterEach((to,from)=>{ console.log("后置路由守卫") if(to.meta.title){ document.title=to.meta.title //修改网页的title }else{ document.title="默认标题" } })Vue——组件间守卫
import About from '../pages/About' import Home from '../pages/Home' import News from '../pages/News' import Detail from '../pages/Detail' export default new VueRouter({ routes:[ { path:'/about', component:About, meta:{isAuth:true,title:'关于'} }, { path:'/home', component:Home, meta:{isAuth:true,title:'标题'} children:[ { path:'news', component:News, meta:{isAuth:true} children:[ path:'detail', component:Detail props($route){ return { id:$route.query.id, title:$route.query.title } ] } ] } ] })About.vue组件
<template> <h2>我是ABOUT内容</h2> </template> <script> export default{ name:'About' mounted(){ console.log('@@@',this.$route) }, beforeRouteEnter(to,from,next){ console.log("组件间路由守卫") if(to.meta.isAuth){ if(localStorage.getItem('school')=="atguigu"){ next() }else{ alert("学校名称不对,无权限访问") } }else{ next() } }, beforeRouterLeave(to,from,next){ next() } } </script>小结:路由守卫
1、作用:对路由进行权限控制
2、分类:全局守卫,独享守卫,组件守卫
3、全局守卫:
4、独享守卫:
5、组件内路由守卫
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。