Vue基本语法

v-if与v-show的生命周期影响

再深刻认识 v-if和v-show以及组件的生命周期
   v-if对组件的生命周期每次都会执行一遍
   而v-show只会执行一遍。

1. scoped 样式的问题

我们需要为一个.vue中的style添加一个scoped属性,以保证样式也是局部的。

<style scoped>
​
</style>
  • app.vue中的样式是全局的

<style>
​
​
.box{
  margin:20px;
  border: 2px solid salmon;
}
​
</style>

2.组件通信(重点)

分两种:

1)父子如何通信

2)非父子之间如何通信

为什么要通信,因为每组件中的data只能在当前使用,所以要用一些通信手段 。

2.1 父组件向子组件传递数据

2.1.1语法

<template>
  <div class="box">
      <h2>parent : 父传子语法</h2>
      username: {{username}}
​
      <!-- 1. 在使用子组件以绑定属性的方式传递数据 -->
      <v-child 
        a="my is a" 
        :b="20" 
        :c="username"
        :age="age"
      ></v-child>
  </div>
</template>
​
<script>
​
import vChild from './child.vue'
​
export default {
  components:{
    vChild
  },
  data(){
    return {
      username:'鲁班',
      age:30
    }
  }
}
</script>
​
<style>
​
</style>
<template>
  <div class="box">
      <h2>child</h2>
      <!-- 3. 在页面中使用父亲传递过来的数据 -->
      a: {{ a }}
      <hr>
      b: {{ b }}
      <hr>
      c: {{ c }}
      <hr>
      age: {{age}}
  </div>
</template>
​
<script>
export default {
  //2. 使用props接收
    props:[ 'b','a','c','age' ],
  //4. 在js中访问传递过来的数据
  mounted(){
    console.log( this.b,'b' )
    console.log( this.age,'age' )
  }
}
</script>
​
<style>
​
</style>

2.1.2 父传子案例:教师列表

<template>
  <div class="box">
    <h2>web老师</h2>
    <v-list :teachers="teachers"></v-list>
  </div>
</template>
​
<script>
​
import vList from './vList.vue'
​
export default {
  data() {
    return {
      teachers:[
        {
          id: "w0001",
          username: "web-李老师",
          img: "http://www.ujiuye.com/uploadfile/2019/0109/20190109105342884.jpg",
        },
        {
          id: "w000333",
          username: "霍老师",
          img: "http://www.ujiuye.com/uploadfile/2019/0516/20190516094131820.jpg",
        },
      ]
    };
  },
  components:{
    vList
  }
};
</script>
​
<style scoped>
​
</style>
<template>
  <ul>
    <li v-for="item in teachers" :key="item.id">
      姓名:{{ item.username }}
      <img :src="item.img" alt="" />
    </li>
  </ul>
</template>
​
<script>
export default {
  data() {
    return {};
  },
  props: ["teachers"], //接收父组件传递过来的数据
};
</script>
​
<style scoped>
ul {
  overflow: hidden;
}
ul li {
  float: left;
  margin: 5px;
}
ul li img {
  width: 150px;
  height: 200px;
}
</style>

2.1.3props验证

props的值为{}时,可以做props验证.
​
type(类型) :props做校验时的常见类型:String,Number,Array,Object,Function,Boolean
required(必填项)
validator(验证器)
default(默认值)
<template>
  <div class="box">
      <h2>parent: props数据验证</h2>

    <!-- 15811112222    0371- -->
    <v-child :age="15"></v-child>
    <v-child :tel="tel" :age="110"></v-child>

    {{}}
  </div>
</template>

<script>

import vChild from './vChild.vue'

export default {
  components:{
    vChild
  },
  data(){
    return {
      tel:'15811112223'
    }
  }
}
</script>


<template>
  <div class="box">
      <h2>child</h2>
      {{tel}}
      <hr>
      {{ tel.substring(0,3) + '****' +  tel.substring(7) }}

      <hr>
      age:{{age}}
  </div>
</template>

<script>
export default {

  //type,required,default
  //自定义验证规则: validator
  props:{
    tel:{
      type:String ,//验证数据类型,如果传递的数据不符合数据类型,则报错
      default(){
          return '15688883333'//如果未传则默认值生效
      }
    },
    age:{
      required:true,//必须传
      type:Number,//年龄应该是个数值类型
      validator(value){ //自定义验证规则。
          // 1-130
          //console.log( value,'就是属性具体的值' );
          //return 一个布尔值
          return   value >=1 && value <= 130
      }
    }
  }
}
</script>

2.2 子组件向父组件传递数据

子传父:
	1.必须触发事件
	
子组件:通过触发$emit来触发自定义事件
父组件:通过触发自定义事件来接收数据

注意:  父组件中通过触发自定义事件时,传递的参数需要通过$event来传递,但是$event可以省略

2.2.1 语法

<template>
  <div class="box">
      <h4>子传父</h4>

    <!-- 
        1. 父亲通过子组件中先传递一个函数,以绑定事件( 自定义事件 )的方式去传递
        2. 子组件中去触发,父组件传递的这个函数,子组件中不用接收,自动会绑定到子组件实例上
        
     -->
    username: {{ username }}
     <!-- <button @click></button> -->
    <v-child @f="parentfn"></v-child>

  </div>
</template>

<script>

import vChild from './vChild.vue'
export default {
    data(){
        return {
            username:'ls'
        }
    },
    components:{
        vChild
    },
    methods:{
        parentfn(e){ //e 就是事件对象,其实就是接收子组件传递过来的数据
            console.log( 'my is parentfn',e );
            this.username = e.username //传递给父组件数据,同时修改父组件的username值
        }
    }
}
</script>


<template>
  <div class="box">
      <h4>child</h4>

      <button @click="sonFn">触发父组件的f事件</button>
  </div>
</template>

<script>
export default {
  methods:{
    sonFn(){
       console.log( 'sonfn 点击事件' );

      //触发父组件的f事件  this.$emit( 事件名,传递实际数据 )
      //console.log( this )
      this.$emit('f' ,{ username:'zs',age:18 } )
    }
  }
}
</script>

2.2.2 子传父应用

用户和你的网站进行交互了,会用的多一点。加入购物车/登录/注册

<template>
  
  <div class="box">
      <h4>子传父应用</h4>

      <!-- <div class="mask" v-if="isShow">
            <span>登录成功</span>
      </div> -->

      <v-toast 
        v-if="isShow" 
        @hide="isShow=false"
        :msg="msg"
      ></v-toast>

      <div class="box">
          <h5>登录</h5>
          <!-- <button @click="isShow = true">登录按钮</button> -->
          <button @click="login">登录按钮</button>
          
      </div>
      
      <div class="box">
          <h5>注册</h5>
          <!-- <button @click="isShow = true">注册按钮</button> -->
          <button @click="register">注册按钮</button>
      </div>
      
      <div class="box">
          <h5>加入购物车</h5>
          <button>加入购物车按钮</button>
      </div>

  </div>
</template>

<script>

import vToast from './Toast.vue'

export default {
    data(){
        return {
            isShow:false,
            msg:'加入购物车成功'
        }
    },
    components:{
        vToast
    },
    mounted(){
        
    },
    methods:{
        login(){
            console.log( 'login' );
            this.isShow = true
            this.msg = '登录失败'
        },
        register(){
            console.log( 'register' );
             this.msg = '注册成功'
            this.isShow = true
        }
    }
}
</script>

<template>
  <div>
      <!-- 一个弹框组件 -->
      <div class="mask">
            <span>{{msg}}</span>
      </div>
  </div>
</template>

<script>
export default {
    props:[ 'msg' ],
    mounted(){
        //console.log( 'toast弹框挂载成功了,并开启了一个定时器' );
        setTimeout(()=>{  //箭头函数中的this是上层环境
            console.log( '我要把show改成false' );
            this.$emit( 'hide' )
        },2000)
    }
}
</script>


<style scoped>
.mask{
    width: 100vw;
    height: 100vh;
    position: absolute;
    top:0;
    left: 0;
}
.mask span{
    display: inline-block;
    position:absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50% -50%);
    background-color: rgba(0,0,0,0.6);
    color: #fff;
    padding: 10px 20px;
    border-radius: 20px;
}
</style>

2.3 父传子总结

父传子,父组件传递数据给子组件,默认是父变,子变;子变,父不变,还报错

直接修改:父变,子变,子变,父变,还不报错 ,传递对象。因为本质上对象是引用类型

间接修改:子组件想要修改父组件的值,使用子传父。$emit

<template>
  <div class="box">
    <h4>父传子,子传父总结</h4>

    <!-- 
        父传子,父组件传递数据给子组件,默认是父变,子变;子变,父不变,还报错 
        直接修改:父变,子变,子变,父变,还不报错 ,传递对象。因为本质上对象是引用类型
        间接修改:子组件想要修改父组件的值,使用子传父。$emit
       -->

    username:{{ username }}
    <hr />
    <input type="text" v-model="username" />
    <hr />
    persons:{{ persons.username }}
    <hr />
    <input type="text" v-model="persons.username" />

    <v-child :username="username" :persons="persons"></v-child>
  </div>
</template>

<script>
import vChild from "./vChild.vue";
export default {
  components: {
    vChild,
  },
  data() {
    return {
      username: "zs",
      persons: {
        username: "ls",
        age: 20,
      },
    };
  },
};
</script>

<style>
</style>
<template>
  <div class="box">
      <h4>child</h4>
      username:{{username}}
      <hr>
      <input type="text" v-model="username">
      <hr>
      persons:{{ persons.username }}
      <hr>
      <input type="text" v-model="persons.username">
  </div>
</template>

<script>
export default {
  props:[ 'username','persons' ]
}
</script>

2.4 非父子组件之间通信

eventBus:事件总线 (了解), 子传父的原理其实就是事件总线 。

实现非父子组件通信有三种:
	1.eventBus   前提: A  B需要同时存在
	2.本地存储  localStorage  sessionStorage
	3.vuex(状态管理模式): 重点
	4.cookie/session
  • index.vue

<template>
  <div class="box">
      <h4>非父子之间的通信</h4>

        <!-- 
            事件总线:eventBus
            事件的订阅与发布:事件的兼听和触发

            谁要数据谁就绑定事件兼听的函数,谁给数据谁就触发事件
            A要B里的数据。A绑定一个事件兼听,B触发A的事件

            步骤:
            1. 在main.js中添加如下代码
                Vue.prototype.$eventBus = new Vue()
                    就相当于一个公共的池子
                
            2. 在任意文件中的this实例上都可以到 this.$eventBus 就可以访问到
                因为每个.vue组件实例对象都继承于Vue构造函数
                但是每个this是当前组件的实例对象,而且每个页面之间是不共享的
            3. A要B里的数据。A绑定一个事件兼听,B触发A的事件
                3.1 A绑定一个事件兼听
                this.$eventBus.$on(事件,事件函数)
                3.2 B触发A中兼听的事件函数,并且可以传参
         -->

      <v-a></v-a>
      <v-b></v-b>
  </div>
</template>

<script>
import vA from './vA.vue'
import vB from './vB.vue'
export default {
    components:{
        vB,
        vA
    },
    mounted(){
        // console.log( this,'index.vue' );
        // console.log( this.$aa,'---aa--' );
        console.log( this.$eventBus,'index.vue' );
    }
}
</script>

<style>

</style>
  • vA.vue

<template>
  <div class="box">
    <h4>a</h4>
    {{ username }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      username: "鲁肃",
    };
  },
  mounted() {
    //console.log( this.$eventBus,'a.vue' );
    this.$eventBus.$on("aEvent", (e) => {
      console.log("触发了aEvent事件", e);
      this.username = e.username
    });
  },
};
</script>

<style>
</style>
  • vB.vue

<template>
  <div class="box">
      <h4>b</h4>
      <button @click="bFN">触发A中的事件</button>
  </div>
</template>

<script>
export default {
    methods:{
        bFN(){
           this.$eventBus.$emit('aEvent',{ username:'鲁班' }) 
        }
    }
}
</script>

<style>

</style>

3.ref属性

在vue组件中,系统提供了一个属性ref,
往html内置标签或组件身上绑定ref属性,
在js中可以通过 this.$refs.ref的属性值 访问到DOM节点或子组件

3.1 ref操作普通DOM元素

3.2 ref属性操作子组件(重点)

<template>
  <div class="box aa">
      <h4>ref选择DOM-操作组件</h4>

      <!-- 1. 为内置标签添加ref -->
      <button ref="btn1">按钮</button>

      <button ref="btn2">按钮</button>


    <!-- 2. 为组件添加ref,可以在父组件中直接访问子组件中的数据和方法 -->
    <v-child ref="a"></v-child>
  </div>
</template>

<script>

import vChild from './vChild.vue'

// 在js中通过this.$refs获取
export default {
    mounted(){
        // console.log( this.$refs )
        // console.log( this )
        this.$refs.btn1.style.background = 'red'
        this.$refs.btn2.style.background = 'yellow'

        // console.log( this.$refs.a.username );
         this.$refs.a.username = 'ls' //可以直接修改子组件中的数据
        // this.$refs.a.fn()
    },
    components:{
        vChild
    }
}
</script>

<style>

</style>
<template>
  <div class="box">
      <h4>child</h4>
      username:{{ username }}
  </div>
</template>

<script>
export default {
    data(){
        return {
            username:'zs'
        }
    },
    methods:{
        fn(){
            console.log( 'child fn' );
        }
    }
}
</script>

<style>

</style>

4.is动态组件: 了解

主要是解决一些组件嵌套的问题,componet内置组件

<template>
	<div>
        <!-- 
        什么时候用is。
        ul应该嵌套  li
        table应该嵌套  tr,
        那么在li和tr身上使用动态的is属性来绑定组件
       -->
      <!-- <ul>
          <li is="v-a"></li>
      </ul>
      <table>
          <tr is="v-b"></tr>
      </table> -->

      <!-- component 动态组件 -->

      <button @click="cname='v-b'">登录</button>
      <button @click="cname='v-a'">注册</button>

      <component :is="cname"></component>
    </div>
</template>
<script>
import vA from './vA.vue'
import vB from './vB.vue'
export default {
  components:{
    vA,
    vB
  },
  data(){
    return {
      cname:'v-a'
    }
  }
}
</script>

5. 脚手架使用动画

animate.css

<!-- 
        使用动画
        1. 下载 npm i animate.css
        2. 在main.js中引入animate.css
       -->
       <!--  leave-active-class="animate__animated animate__headShake" -->
       <transition 
         enter-active-class="animate__animated animate__headShake"
        
        >
          <component :is="cname"></component>
       </transition>

6.插槽

vue中提供了 一个新的组件slot
书写格式:
	<slot></slot>

6.1 匿名插槽

没有名称的槽口称之为匿名槽口
<v-header>
      <!-- 放到子组件中 slot插槽中 -->
      <button>回到首页1</button>
      <button>回到首页2</button>
    </v-header>

    
  <h5>京东的头部</h5>
      <!-- 1. 匿名插槽 -->
      <h6>1. 匿名插槽</h6>
      <slot></slot>  

6.2 具名插槽

    <v-header>
      <button slot="shang">回到首页33</button>
      <button slot="xia">回到首页44</button>
    </v-header>
<!-- 2. 具名插槽 -->
      <h6>2. 具名插槽</h6>
      <slot name="shang"></slot>
      <slot name="xia"></slot>

6.3 插槽作用域(重要)

1.接收子组件通过槽口传递的所有数据的方式有两种:
  slot-scope:指令
  v-slot:指令
2.slot-scope或者v-slot对应的属性值名可以自定义
3.此时的scope的值就是子组件通过slot遍历的每一项
<!-- 
        什么时候用作用域插槽
        1. 有时候不确定要往slot中放什么标签才用slot插槽
        2. 还要传递数据给子组件通过父传子
        3. 还要再让子组件再通过插槽再返回给父组件(因为不确定此处要放什么标签)
                每个人都加个age过来
       -->
    <v-two :persons="persons">
      <!-- 用v-slot或slot-scope接收 子组件中通过slot传递过来的数据 -->
      <!-- 
          v-slot : 这是新提出的
          slot-scope: 这是vue刚出来的时候提供的
       -->
      <template v-slot="scope">
        <ul >
          <!-- {{scope}} -->
          <li v-for="item in scope.rows" :key="item.id">
            {{ item.username }} -- {{ item.age }}
          </li>
        </ul>
      </template>
    </v-two>
    <v-two>
      <!-- <template slot-scope="scope"> -->
        <ol slot-scope="scope">
          <!-- {{scope}} -->
          <li v-for="item in scope.rows" :key="item.id">
            {{ item.username }} -- {{ item.age }}
          </li>
        </ol>
      <!-- </template> -->
    </v-two>

<script>
export default {
  components: {
    vHeader,
    vTwo,
  },
  data() {
    return {
      persons: [
        { id: 1, username: "zs" },
        { id: 2, username: "ls" },
      ],
    };
  },
};
</script>
<template>
  <div class="box">
    <h5>two:作用域插槽</h5>
    <slot :rows="rows"></slot>
  </div>
</template>

<script>
export default {
  props: ["persons"],
  data() {
    return {
      //这个数据就是子组件返回给父组件
      rows: [
        { id: 1, username: "zs" ,age:20},
        { id: 2, username: "ls" ,age:21},
      ],
    };
  },
  mounted() {},
};
</script>

<style>
</style>

7.mixin混入(了解)

1.mixin是一个对象,可以将这个对象混入到组件中.
2.组件中的选项都可以在mixin对象中声明

作用:
将组件中共享的数据一般存放在mixin中,

比如:你的项目都做好了,(组件都已经完成了),需求:我关心组件中的访问时间
  • vMixins.vue

<template>
  <div class="box">
      <h5>mixin:混入</h5>

      <v-a></v-a>
  </div>
</template>

<script>

import vA from './vA.vue'

import mixinsa from './mixins'

export default {
  components:{
    vA
  },
  data(){
    return {
      username:'混入中的username'
    }
  },
  mixins:[ mixinsa ], //植入混入对象
  // mounted(){
  //   console.log(this.accesstime,'vMixins.vue')
  // }
}
</script>

<style>

</style>
  • mixins.js

/*
    1. 创建混入文件
    会导出一个对象
        这个对象参考组件中的对象即可
*/ 

export default {
    data(){
        return {
            accesstime: new Date().toLocaleDateString() + new Date().toLocaleTimeString()
        }
    },
    mounted(){
        console.log(this.accesstime,'vMixins.vue')
      }
}

8.缓存组件(了解)

vue中提供了一个组件keep-alive,作为缓存组件.

使用keep-alive包裹的组件就是缓存组件.

8.1 缓存组件钩子函数

  • activated 组件激活时的状态

  • deactivated 组件失活时的状态

<template>
  <div class="box">
    <h4>keepAlive: 缓存组件</h4>
    <!-- 
        优化你的组件加载的。
       -->
    <button @click="flag = true">加载A</button>
    <button @click="flag = false">加载B</button>

    <!-- <v-a v-show="flag"></v-a>
    <v-b v-show="!flag"></v-b> -->

    <keep-alive>
      <v-a v-if="flag"></v-a>
      <v-b v-else></v-b>
    </keep-alive>

    <!-- <v-a v-if="flag"></v-a>
    <v-b v-else></v-b> -->
  </div>
</template>

<script>
import vA from "./vA.vue";
import vB from "./vB.vue";
export default {
  components: {
    vB,
    vA,
  },
  data() {
    return {
      flag: true, //true A   false B
    };
  },
};
</script>

<style>
</style>

A.vue

<template>
  <div class="box">
    <h2>a</h2>
  </div>
</template>

<script>
export default {
  /*
     加上keep-alive以后,组件就不会触发   created、destroyed等生命周期了
  */
  created() {
    console.log("请求了a页面的ajax数据列表");
  },
  mounted() {
    //console.log("绑定了a的window.scroll事件");
    // console.log("绑定了a的window.scroll事件");
  },
  destroyed() {
    // console.log("解除了a的window.scroll事件");
  },
  activated() {
    console.log("a组件激活了,显示了");
    console.log("绑定了a的window.scroll事件");
  },
  deactivated() {
    console.log("a组件失活了,不显示了");
    console.log("解除了a的window.scroll事件");
  },
};
</script>

<style>
</style>

  • index.vue

    添加按钮: 展示form.vue

    import list.vue

    import form.vue

  • list.vue

    展示表格

  • form.vue

    添加数据的表单

修改功能是扩展。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值