• Vue记录(上篇)


    Hello world案例

    DOCTYPE html>
    <html lang="zh-CN">
    
    <head>
      <meta charset="UTF-8">
      <title>初识Vuetitle>
      
      <script type="text/javascript" src="./vue.js">script>
      <script type="text/javascript">
        Vue.config.productionTip = false  //设置为 false 以阻止 vue 在启动时生成生产提示。
      script>
    head>
    <body>
      
      <div id="root">
        <h1>Hello,{{ name }}h1>
      div>
    body>
     <script>
        //创建Vue实例
        new Vue({
          el: '#root',  //el用于指定当前Vue实例为那个容器服务,值为CSS选择器字符串
          data: {  //data中用于存储数据,数据供el所指容器使用,之暂时先写成一个对象
            name: '尚硅谷'
          }
        })
      script>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    1.想让Vue工作就必须创建一个Vue实例,且要传入一个配置对象
    2.root容器里的代码依然符合HTML规范,只不过加入了特殊Vue语法
    3.root容器中代码被称为Vue模板
    4.Vue实例和容器是一一对应的
    5.真实开发中只有一个Vue实例,并且会配合着组件一起使用
    6.{{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中所有属性;
    7.一旦data中数据发生改变,模板中用到该数据的地方也会自动更新。

    模板语法

    在这里插入图片描述

    DOCTYPE html>
    <html lang="zh-CN">
    
    <head>
      <meta charset="UTF-8">
      <title>模板语法title>
      
      <script type="text/javascript" src="./vue.js">script>
      <script type="text/javascript">
        Vue.config.productionTip = false  //设置为 false 以阻止 vue 在启动时生成生产提示。
      script>
    head>
    
    <body>
      
      <div id="root">
        <h1>插值语法h1>
        <h3>你好,{{ name }}h3>
        <hr />
        <h1>指令语法h1>
        <a v-bind:href="school.url" v-bind:x="hello">点我去{{school.name}}学习1a>
        
      div>
    body>
    
    <script>
      new Vue({
        el: '#root',
        data: {
          name: 'jack',
          school: {
            url: 'http://www.atguigu.com',
            name: '尚硅谷'
          }
    
        }
      })
    script>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    Vue模板语法有2大类:
    1.插值语法:
    功能:用于解析标签体内容
    写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性
    2.指令语法:
    功能:用于解析标签(标签属性,标签体内容,绑定事件…)
    备注:Vue中有很多指令,形式都为v-???,v-bind只是其中一个

    数据绑定

    在这里插入图片描述

    DOCTYPE html>
    <html lang="zh-CN">
    
    <head>
      <meta charset="UTF-8">
      <title>数据绑定title>
      
      <script type="text/javascript" src="./vue.js">script>
      <script type="text/javascript">
        Vue.config.productionTip = false  //设置为 false 以阻止 vue 在启动时生成生产提示。
      script>
    head>
    
    <body>
      
      <div id="root">
        
       单向数据绑定:<input type="text" v-bind:value="name">
       <br/>
       双向数据绑定:<input type="text" v-model:value="name">
       <br/>
    
       
       单向数据绑定:<input type="text" :value="name">
       <br/>
       双向数据绑定:<input type="text" v-model="name">
       <br/>
    
       
       
      div>
    body>
    
    <script>
      new Vue({
        el:'#root',
        data:{
          name:'尚硅谷'
        }
      })
    script>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    Vue中有2种数据绑定的方式:
    1.单向绑定(v-bind):数据只能从data流向页面
    2.双向绑定(v-model):数据不仅能从data流向页面,也可以从页面流向data
    备注:
    1.双向绑定一般都应用在表单元素上(如:input,select)
    2.v-model:value可以简写为v-model,v-model默认收集的就是value。

    el与data两种写法

    • el
    DOCTYPE html>
    <html lang="zh-CN">
    
    <head>
      <meta charset="UTF-8">
      <title>title>
      
      <script type="text/javascript" src="./vue.js">script>
      <script type="text/javascript">
        Vue.config.productionTip = false  //设置为 false 以阻止 vue 在启动时生成生产提示。
      script>
    head>
    
    <body>
      
      <div id="root">
       <h1>你好,{{name}}h1>
      div>
    body>
    
    <script>
      // el的两种写法
      
      const v = new Vue({
        // el:'#root', //第一种写法
        data:{
          name:'尚硅谷'
        }
      })
      console.log(v);
      v.$mount('#root')  //灵活,第二种写法
    
      // setTimeout(()=>{
      //   v.$mount('#root')
      // },1000)
    
    script>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • data
    DOCTYPE html>
    <html lang="zh-CN">
    
    <head>
      <meta charset="UTF-8">
      <title>title>
      
      <script type="text/javascript" src="./vue.js">script>
      <script type="text/javascript">
        Vue.config.productionTip = false  //设置为 false 以阻止 vue 在启动时生成生产提示。
      script>
    head>
    
    <body>
      
      <div id="root">
       <h1>你好,{{name}}h1>
      div>
    body>
    
    <script>
      // data的两种写法
    
      const v = new Vue({
        el:'#root', 
        //第一种写法:对象式
        // data:{
        //   name:'尚硅谷'
        // }
    
        //第二种写法:函数式
        data(){
          return{
            name:'尚硅谷',
          }
        }
      })
    script>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    1. data两种写法如何选择:以后学习到组件,data必须使用函数式,否则会报错
    2. 重要原则:一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了
    • MVVM模型
    DOCTYPE html>
    <html lang="zh-CN">
    
    <head>
      <meta charset="UTF-8">
      <title>理解MVVMtitle>
      
      <script type="text/javascript" src="./vue.js">script>
      <script type="text/javascript">
        Vue.config.productionTip = false  //设置为 false 以阻止 vue 在启动时生成生产提示。
      script>
    head>
    
    <body>
      
      
      <div id="root">
       <h1>学校名称:{{name}}h1>
       <h1>学校地址:{{address}}h1>
       <h1>测试1:{{1+1}}h1>
       <h1>测试2:{{$options}}h1>
       <h1>测试3:{{_c}}h1>
      div>
    body>
    
    <script>
      // ViewModel
      const vm = new Vue({
        el:'#root',
        // Model
        data:{
          name:'尚硅谷',
          address:'北京'
        }
      })
      console.log(vm);
    script>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    data中所有属性,最后都出现在vm身上
    vm身上所有的属性及Vue原型上所有的属性,在Vue模板中都可以直接使用

    数据代理

    回顾Object.defineproperty方法

    DOCTYPE html>
    <html lang="zh-CN">
    
    <head>
      <meta charset="UTF-8">
      <title>回顾Object.defineproperty方法title>
      
      <script type="text/javascript" src="./vue.js">script>
      <script type="text/javascript">
        Vue.config.productionTip = false  //设置为 false 以阻止 vue 在启动时生成生产提示。
      script>
    head>
    
    <body>
      <script type="text/javascript">
        let num = 18
        let person = {
          name: '张三',
          sex: '男',
          // age:18
        }
    
        // 此方法添加属性不可枚举
    
        Object.defineProperty(person, 'age', {
          // value: 18,
          // enumerable: true, //控制属性是否可以枚举,默认false
          // writable: true, //控制属性是否可以被修改,默认false
          // configurable: true, //控制属性是否可以被删除,默认false
    
          // 当有人读取person 的age属性时,get函数(getter)就会被调用,且返回值就是age值
          get() {
            return num
          },
    
          // 当有人修改person 的age属性时,set函数(setter)就会被调用,且返回修改的具体值
          set(value){
            console.log('有人修改了age值,qie修改后值为:',value)
            number = value
          }
        })
    
        // console.log(Object.keys(person))
        console.log(person);
      script>
    
    body>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    什么是数据代理

    DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <title>什么是数据代理title>
    head>
    <body>
      
      <script type="text/javascript">
        let obj = {x:100}
        let obj1 = {y:200}
    
        Object.defineProperty(obj1,'x',{
          get(){
            return obj.x
          },
    
          set(value){
            obj.x = value
          }
        })
      script>
      
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    Vue中的数据代理

    在这里插入图片描述

    1. Vue中数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)
    2. 好处:更加方便操作data中数据
    3. 原理:
      通过Object.defineProperty()把data对象中所有属性添加到vm上。
      为每一个添加到vm上的属性,都指定一个getter/setter。
      在getter/setter内部去操作data中对应的属性。

    事件处理

    绑定监听

    在这里插入图片描述

    DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <title>事件的基本使用title>
      <script type="text/javascript" src="./vue.js">script>
      <script>Vue.config.productionTip = false  //阻止vue在启动时生成生产提示sscript>
    head>
    <body>
      <div id="root">
        <h2>欢迎来到{{name}}学习h2>
        <button v-on:click="showInfo1">点我提示信息1(不传参)button>
        <button @click="showInfo2($event,66)">点我提示信息2(传参)button>
      div>
    body>
    
    <script type="text/javascript">
      const vm = new Vue({
        el:'#root',
        data:{
          name:'尚硅谷',  
        },
        methods:{
          showInfo1(event){
            // console.log(this);  //此处this是vm
            alert('同学你好!')
          },
          showInfo2(event,number){
            console.log(event,number);
            // console.log(this);  //此处this是vm
            alert('同学你好!!')
          }
        }
      })
     
    script>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    事件的基本使用:

    1. 使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名
    2. 事件的回调需要配置在methods对象中,最终会在vm上
    3. methods中配置的函数,不要用箭头函数,否则this就不是vm
    4. methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象
    5. @click=“demo” 和 @click=“demo($event)” 效果一致,但后者可以传参

    事件修饰符

    在这里插入图片描述

    Vue中的事件修饰符
    1)prevent: 阻止默认事件(常用);
    2)stop:阻止事件冒泡(常用);
    3)once:事件只触发一次(常用);
    4)capture:使用事件的捕获模式;
    5)self:只有event.target是当前操作的元素时才触发事件;
    6)passive: 时间的默认行为立即执行,无需等待事件回调执行完毕。

    DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <title>事件修饰符title>
      <script type="text/javascript" src="./vue.js">script>
      <script>Vue.config.productionTip = false  //阻止vue在启动时生成生产提示script>
      <style>
        * {
          margin-top: 20px;
        }
        .demo1 {
          height: 50px;
          background-color: skyblue;
        }
        .box1 {
          padding: 5px;
          background-color: skyblue;
        }
        .box2 {
          padding: 5px;
          background-color: orange;
        }
        .list {
          width: 200px;
          height: 200px;
          background-color: peru;
          overflow: auto;
        }
        li {
          height: 100px;
        }
      style>
    head>
    <body>
      <div id="root">
        <h2>欢迎来到{{name}}学习h2>
        
        <a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息a>
    
        
        <div class="demo1" @click="showInfo">
          <button @click.stop="showInfo">点我提示信息button>
        div>
    
        
        <button @click.once="showInfo">点我提示信息button>
    
        
        <div class="box1" @click.capture="showMsg(1)">
          div1
          <div class="box2" @click.capture="showMsg(2)">
            div2
          div>
        div>
    
        
        <div class="demo1" @click.self="showInfo">
          <button @click="showInfo">点我提示信息button>
        div>
    
        
        <ul @wheel.passive="demo" class="list">
          <li>1li>
          <li>2li>
          <li>3li>
          <li>4li>
        ul>
      div>
    body>
    
    <script type="text/javascript">
       new Vue({
        el:'#root',
        data:{
          name:'尚硅谷',  
        },
        methods:{
          showInfo(e){   
            // alert('同学你好!')
            console.log(e.target)
          },
          showMsg(msg){
            console.log(msg);
          },
          demo(){
            for (let index = 0; index < 10000; index++) {
              console.log('#')
            }
            console.log('累坏了')
          }
        }
      })
     
    script>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    键盘事件

    在这里插入图片描述

    1. Vue中常用按键别名
      回车=>enter
      删除=>delete(捕获“删除”和“退格”键)
      退出=>esc
      空格=>space
      换行=>tab(必须配合keydown使用)
      上 => up
      下 => down
      左 => left
      右 => right
    2. 如果vue中没有定义想要使用的键的话,可以通过e输出e.key,e.keyCode来查看键盘上按键的名称和编码。
      如果按键名称是驼峰命名的话,要把单词的首字母都改成小写,并且用-连接。
    3. 系统修饰符(用法特殊):ctrl、alt、shift、meta
      (1)、配合keyup使用:按下修饰符键的同时,再按下其他键,随后释放其他键,事件才被触发。
      (2)、配合keydown使用:正常触发事件。

    计算属性

    计算属性-computed在这里插入图片描述

    DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <title>姓名案例_插值语法实现title>
      <script type="text/javascript" src="./vue.js">script>
      <script>Vue.config.productionTip = false  //阻止vue在启动时生成生产提示script>
    head>
    <body>
      <div id="root">
        姓:<input type="text" v-model="firstname"><br/><br/>
        名:<input type="text" v-model="lastname"><br/><br/>
        姓名:<span>{{firstname.slice(0,3)}}-{{lastname}}span>
      div>
    body>
    
    <script type="text/javascript">
       new Vue({
        el:'#root',
        data:{
          firstname:'张',
          lastname:'三'  
        },
        methods:{
         showInfo(e){
          console.log(e.key,e.keyCode);
          // console.log(e.target.value);
         }
        }
      })
     
    script>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述

    DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <title>姓名案例_methods实现title>
      <script type="text/javascript" src="./vue.js">script>
      <script>Vue.config.productionTip = false  //阻止vue在启动时生成生产提示script>
    head>
    <body>
      <div id="root">
        姓:<input type="text" v-model="firstname"><br/><br/>
        名:<input type="text" v-model="lastname"><br/><br/>
        姓名:<span>{{fullName()}}span>
      div>
    body>
    
    <script type="text/javascript">
       new Vue({
        el:'#root',
        data:{
          firstname:'张',
          lastname:'三'  
        },
        methods:{
          fullName(){
            return this.firstname+'-'+this.lastname
          }
        }
      })
     
    script>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <title>姓名案例_计算属性实现title>
      <script type="text/javascript" src="./vue.js">script>
      <script>Vue.config.productionTip = false  //阻止vue在启动时生成生产提示script>
    head>
    <body>
      <div id="root">
        姓:<input type="text" v-model="firstname"><br/><br/>
        名:<input type="text" v-model="lastname"><br/><br/>
        姓名:<span>{{fullName}}span><br/><br/>
        姓名:<span>{{fullName}}span><br/><br/>
        姓名:<span>{{fullName}}span><br/><br/>
        姓名:<span>{{fullName}}span>
      div>
    body>
    
    <script type="text/javascript">
       const vm = new Vue({
        el:'#root',
        data:{
          firstname:'张',
          lastname:'三',
        },
        computed:{
          fullName:{
            // get作用:当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
            // get什么时候调用:
            // 1.初次读取fullName时
            // 2.所依赖数据发生变化时
            get(){
              console.log('get被调用了')
              return this.firstname+'-'+this.lastname
            },
    
            // set什么时候调用:
            // 1.fullName被修改时
            set(value){
              console.log('set',value)
              const arr = value.split('-')
              this.firstname = arr[0]
              this.lastname = arr[1]
            }
          }
        }
      })
     
    script>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    在这里插入图片描述

    计算属性:

    1. 定义:要用的属性不存在,要通过已有属性计算得来。
    2. 原理:底层借助了Object.defineproperty方法提供的getter和setter。
    3. get函数什么时候执行?
      初次读取时会执行一次。
      当依赖的数据产生变化时会再次调用
    4. 优势:与methods方法相比,内部具有缓存的机制,效率更高,调试方便
    5. 备注:
      计算属性最终会出现在vm上,直接读取使用即可。
      如果计算属性需要被修改,则必须去写set函数去响应修改,且set中要引起计算时依赖的数据发生变化。

    计算属性简写(只考虑读取不考虑修改时才可以使用简写)

    DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <title>计算属性简写title>
      <script type="text/javascript" src="./vue.js">script>
      <script>Vue.config.productionTip = false  //阻止vue在启动时生成生产提示script>
    head>
    <body>
      <div id="root">
        姓:<input type="text" v-model="firstname"><br/><br/>
        名:<input type="text" v-model="lastname"><br/><br/>
        姓名:<span>{{fullName}}span><br/><br/>
      div>
    body>
    
    <script type="text/javascript">
       const vm = new Vue({
        el:'#root',
        data:{
          firstname:'张',
          lastname:'三',
        },
        computed:{
    
          /*
          // 完整写法:
    
          fullName:{
            // get作用:当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
            // get什么时候调用:
            // 1.初次读取fullName时
            // 2.所依赖数据发生变化时
            get(){
              console.log('get被调用了')
              return this.firstname+'-'+this.lastname
            },
    
            // set什么时候调用:
            // 1.fullName被修改时
            set(value){
              console.log('set',value)
              const arr = value.split('-')
              this.firstname = arr[0]
              this.lastname = arr[1]
            }
          }
          */
    
          // 简写(只考虑读取不考虑修改时才可以使用简写)
          fullName(){
            console.log('get被调用了')
            return this.firstname+'-'+this.lastname
          }
          }
      })
     
    script>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    监视属性-watch

    在这里插入图片描述

    DOCTYPE html>
    <html lang="zh-CN">
    
    <head>
      <meta charset="UTF-8">
      <title>监视属性title>
      <script type="text/javascript" src="./vue.js">script>
      <script>Vue.config.productionTip = false  //阻止vue在启动时生成生产提示script>
    head>
    
    <body>
      <div id="root">
        <h2>今天天气很{{info}}h2>
        
        
        <button @click="changeWeather">切换天气button>
      div>
    body>
    
    <script type="text/javascript">
      const vm = new Vue({
        el: '#root',
        data: {
          isHot: true
        },
        computed: {
          info() {
            return this.isHot ? '炎热' : '凉爽'
          }
        },
        methods: {
          changeWeather() {
            this.isHot = !this.isHot
          }
        },
        // watch:{
        //   isHot:{
        //     // 初始化时让handler调用一下
        //     immediate:true,
        //     // handler什么时候调用?当isHot发生改变时
        //     handler(newValue,oldValue){
        //       console.log('isHot被修改了',newValue,oldValue)
        //     }
        //   }
        // }
      })
    
      vm.$watch('isHot', {
        // 初始化时让handler调用一下
        immediate: true,
        // handler什么时候调用?当isHot发生改变时
        handler(newValue, oldValue) {
          console.log('isHot被修改了', newValue, oldValue)
        }
      }
      )
    
    script>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    在这里插入图片描述

    监视属性watch:

    1. 当被监视的属性变化时,回调函数自动调用,进行相关操作
    2. 监视属性必须存在才能进行监视
    3. 两种写法:
      (1).new Vue时传入watch配置
      (2)通过vm.$watch监视

    深度监视

    DOCTYPE html>
    <html lang="zh-CN">
    
    <head>
      <meta charset="UTF-8">
      <title>深度监视title>
      <script type="text/javascript" src="./vue.js">script>
      <script>Vue.config.productionTip = false  //阻止vue在启动时生成生产提示script>
    head>
    
    <body>
      <div id="root">
        <h2>今天天气很{{info}}h2>
        
        
        <button @click="changeWeather">切换天气button>
        <hr/>
        <h3>a的值时:{{numbers.a}}h3>
        <button @click="numbers.a++">点我让a+1button>
        <hr/>
        <h3>b的值时:{{numbers.b}}h3>
        <button @click="numbers.b++">点我让b+1button>
      div>
    body>
    
    <script type="text/javascript">
      const vm = new Vue({
        el: '#root',
        data: {
          isHot: true,
          numbers:{
            a:1,
            b:1
          }
        },
        computed: {
          info() {
            return this.isHot ? '炎热' : '凉爽'
          }
        },
        methods: {
          changeWeather() {
            this.isHot = !this.isHot
          }
        },
        watch:{
          isHot:{
            // 初始化时让handler调用一下
            // immediate:true,
            // handler什么时候调用?当isHot发生改变时
            handler(newValue,oldValue){
              console.log('isHot被修改了',newValue,oldValue)
            }
          },
    
           // 监视多级结构中某个属性变化
          // 'numbers.a':{
          //   handler(newValue,oldValue){
          //     console.log('a被修改了')
          //   }
          // },
    
          // 监视多级结构中所有属性的变化
          numbers:{
            deep:true,
            handler(){
              console.log('numbers改变了')
            }
          }
        }
      })
    script>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    深度监视:
    (1) Vue中的watch默认监测对象内部值的改变(一层)
    (2)配置deep:true可以监测对象内部值的改变(多层)
    备注:
    (1)Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
    (2)使用watch时根据数据的具体结构,决定是否采用深度监视

    深度监视简写

    DOCTYPE html>
    <html lang="zh-CN">
    
    <head>
      <meta charset="UTF-8">
      <title>深度监视title>
      <script type="text/javascript" src="./vue.js">script>
      <script>Vue.config.productionTip = false  //阻止vue在启动时生成生产提示script>
    head>
    
    <body>
      <div id="root">
        <h2>今天天气很{{info}}h2>
        
        
        <button @click="changeWeather">切换天气button>
      div>
    body>
    
    <script type="text/javascript">
      const vm = new Vue({
        el: '#root',
        data: {
          isHot: true,
        },
        computed: {
          info() {
            return this.isHot ? '炎热' : '凉爽'
          }
        },
        methods: {
          changeWeather() {
            this.isHot = !this.isHot
          }
        },
        watch: {
          // 完整写法
          /*
          isHot:{
            // immediate:true,
            // deep:true,  //深度监视
            // 当配置项中只有handler时可以简写
            handler(newValue,oldValue){
              console.log('isHot被修改了',newValue,oldValue)
            }
          },
          */
    
          // 简写
          // isHot(newValue,oldValue){
          //   console.log('isHot被修改了',newValue,oldValue)
          // }
        }
      })
    
      // 正常写法
      vm.$watch('isHot', {
        immediate: true,
        deep: true,  //深度监视
        // 当配置项中只有handler时可以简写
        handler(newValue, oldValue) {
          console.log('isHot被修改了', newValue, oldValue)
        }
      })
    
      // 简写(不可以写成箭头函数)
       vm.$watch('isHot',function(newValue,oldValue){
         console.log('isHot被修改了', newValue, oldValue)
       })
    script>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    watch和computed对比

    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">
        <title>姓名案例_监视属性实现title>
        
        <script type="text/javascript" src="../js/vue.js">script>
    head>
    <body>
        
        <div id="root">
            姓: <input type="text" v-model="firstName"><br><br>
            名: <input type="text" v-model="lastName"><br><br>
            姓名: <span>{{fullName}}span>
        div>
    body>
    <script type="text/javascript">
        Vue.config.productionTip =  false // 阻止 vue 在启动时生成生产提示
     
        new Vue({
            el:"#root",
            data:{
                firstName:'振华中学',
                lastName:'林杨',
                fullName:'振华中学的林杨'
            },
            // methods: {
            //     fullname(){
            //         return this.firstname + '的' + this.lastname
            //     }
            // }
            watch:{
                firstName(val){
                    setTimeout(() => {
                        this.fullName = val + '的' + this.lastName
                        },1000);
                },
                lastName(val){
                    this.fullName = this.firstName + '的' + val
                }
            }
        })
    script>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    computed与watch之间的区别:

    1. computed能完成的功能,watch都可以完成
    2. watch能完成的功能,computed不一定能完成。例如:watch可以进行异步操作

    两个重要的小原则:
    所有被Vue管理的函数,最好写成普通函数,这样this指向才是vm或者组件实例对象。
    所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等)最好写成箭头函数,这样this的指向才是vm或组件实例对象。

    绑定样式

    在这里插入图片描述

    class绑定

    在这里插入图片描述

    style 绑定

    在这里插入图片描述

    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">
        <title>绑定样式title>
        
        <script type="text/javascript" src="../js/vue.js">script>
        <style>
            .basic{
                width: 400px;
                height: 200px;
                border: 2px solid cornflowerblue;
            }
     
            .normal{
                background-color: lightsteelblue;
            }
     
            .happy{
                background-color: cornflowerblue;
            }
     
            .sad{
                background-color: chartreuse;
            }
     
            .sgg1{
                font-size: 20px;
                text-align: center;
            }
     
            .sgg2{
                border-radius: 10px;
            }
     
            .sgg3{
                font-style: inherit;
                background-color: red;
            }
        style>
    head>
    <body>
        
        <div id="root" >
            
            <div class="basic" :class="mood" @click="changeMood">{{name}}>div><br><br>
     
            
            <div class="basic" :class="arr" >{{name}}>div><br><br>
     
            
            <div class="basic" :class="obj" >{{name}}>div><br><br>
     
            
            <div class="basic" :style="style" >{{name}}>div><br><br>
        div>
    body>
    <script type="text/javascript">
        Vue.config.productionTip =  false // 阻止 vue 在启动时生成生产提示
     
        new Vue({
            el:"#root",
            data:{
                name:"尚硅谷",
                mood:'normal',
                arr:['sgg1','sgg2','sgg3'],
                obj:{
                    sgg1:false,
                    sgg2:false,
                    sgg3:false
                },
                style:{
                    fontSize: '40px',
                    color: 'blue'
                }
            },
            methods: {
                changeMood(){
                    const arr = ['normal','happy','sad']
                    this.mood = arr[Math.floor(Math.random()*3)]
                }
            },
        })
    script>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    1.class样式
    写法:class=“xxx” xxx可以是字符串、对象、数组。
    对象写法适用于:要绑定多个样式,个数不确定、名字也不确定。
    数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。

    2.style样式
    :style="{fontSize:xxx}“其中xxx是动态的
    :style=”[a,b]"其中a,b是样式对象

    条件渲染在这里插入图片描述

    DOCTYPE html>
    <html lang="zh-CN">
    
    <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">
      <script type="text/javascript" src="./vue.js">script>
      <title>Documenttitle>
    head>
    
    <body>
      
      <div id="root">
        <h2>当前的n值时{{n}}h2>
        <button @click="n++">点我n+1button>
        
        {name}} -->
        {name}} -->
    
        
        {name}} -->
        {name}} -->
    
        
        
    
        
        <template v-if="n === 1">
          <h2>你好h2>
          <h2>尚硅谷h2>
          <h2>北京h2>
        template>
    
      div>
    body>
    
    <script type="text/javascript">
      new Vue({
        el: '#root',
        data: {
          name: '尚硅谷',
          n: 0
        }
      })
    script>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    条件渲染:

    1. v-if
      写法:
      v-if=“表达式”
      v-else-if=“表达式”
      v-else=“表达式”
      适用于:切换频率比较低的场景
      特点:不展示的DOM元素直接被移除
      注意:v-if可以和v-else-if、v-else一起使用,但结构不能被打断。
    2. v-show
      写法:v-show=“表达式”
      适用于:切换频率较高的场景
      特点:不能展示的DOM元素未被移除,仅仅是使用样式隐藏掉。
    3. 备注:使用v-if时,元素可能无法获取到,而使用v-show一定可以获取到

    列表渲染

    在这里插入图片描述

    DOCTYPE html>
    <html lang="zh-CN">
    
    <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">
      <script type="text/javascript" src="./vue.js">script>
      <title>基本列表title>
    head>
    
    <body>
      
      <div id="root">
        
        <h2>人员h2>
        <ul>
          <li v-for="(p,index) in persons" :key="index">
            {{p.name}}-{{p.age}}
          li>
        ul>
    
        
        <h2>汽车信息h2>
        <ul>
          <li v-for="(value,key) in car" :key="key">
            {{key}}-{{value}}
          li>
        ul>
    
        
        <h2>字符串信息h2>
        <ul>
          <li v-for="(value,key) in str" :key="key">
            {{key}}-{{value}}
          li>
        ul>
    
         
         <h2>字符串信息h2>
         <ul>
           <li v-for="(number,index) in 10" :key="index">
             {{index}}-{{number}}
           li>
         ul>
    
      div>
    body>
    
    <script type="text/javascript">
      new Vue({
        el: '#root',
        data: {
          persons:[
            {id:'001',name:'张三',age:18},
            {id:'002',name:'李四',age:19},
            {id:'003',name:'王五',age:20},
          ],
          car:{
            name:'奥迪A8',
            price:'70万',
            color:'黑色'
          },
          str:'hello'
        }
      })
    script>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    v-for指令:

    1. 用于展示列表数据
    2. 语法:v-for=“(item,index) in xxx” :key=“yyy”
    3. 可遍历:数组、对象、字符串(少)、指定次数(少)

    key原理

    DOCTYPE html>
    <html lang="zh-CN">
    
    <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">
      <script type="text/javascript" src="./vue.js">script>
      <title>key原理title>
    head>
    
    <body>
      
      <div id="root">
        
        <h2>人员h2>
        <button @click.once="add">添加一个王二麻子button>
        <ul>
          <li v-for="(p,index) in persons" :key="p.id">
            {{p.name}}-{{p.age}}
            <input type="text">
          li>
        ul> 
      div>
    body>
    
    <script type="text/javascript">
      new Vue({
        el: '#root',
        data: {
          persons:[
            {id:'001',name:'张三',age:18},
            {id:'002',name:'李四',age:19},
            {id:'003',name:'王五',age:20},
          ]
        },
        methods:{
          add(){
            const p = {id:'004',name:'王二麻子',age:21}
            this.persons.unshift(p)
          }
        }
      })
    script>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    面试题:react、vue中的key有什么作用?(key的内部原理)
    虚拟DOM中key的作用:key是虚拟DOM中对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:

    对比规则:
    旧虚拟DOM中找到了与新虚拟DOM相同的key:

    1. 若虚拟DOM中内容没变, 直接使用之前的真实DOM
    2. 若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
    3. 旧虚拟DOM中未找到与新虚拟DOM相同的key:创建新的真实DOM,随后渲染到到页面

    用index作为key可能会引发的问题
    若对数据进行逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ——> 界面效果没问题, 但效率低
    若结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题 开发中如何选择key?

    最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值
    如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表,使用index作为key是没有问题的

    列表过滤

    DOCTYPE html>
    <html lang="zh-CN">
    
    <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">
      <script type="text/javascript" src="./vue.js">script>
      <title>列表过滤title>
    head>
    
    <body>
      
      <div id="root">
        <h2>人员h2>
        <input type="text" placeholder="请输入名字:" v-model="keyWord">
        <ul>
          <li v-for="(p,index) in filPersons" :key="index">
            {{p.name}}-{{p.age}}-{{p.sex}}
          li>
        ul>
      div>
    body>
    
    <script type="text/javascript">
      new Vue({
        el: '#root',
        data: {
          keyWord: '',
          persons: [
            { id: '001', name: '马冬梅', age: 18, sex: '女' },
            { id: '002', name: '周冬雨', age: 19, sex: '女' },
            { id: '003', name: '周杰伦', age: 20, sex: '男' },
            { id: '004', name: '温兆伦', age: 21, sex: '男' },
          ],
          filPersons: []
        },
        watch: {
          keyWord:{
            immediate:true,
            handler(val) {
              this.filPersons = this.persons.filter((p) => {
                return p.name.indexOf(val) !== -1
              })
            }
          }
        }
      })
    script>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    在这里插入图片描述

    DOCTYPE html>
    <html lang="zh-CN">
    
    <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">
      <script type="text/javascript" src="./vue.js">script>
      <title>列表过滤title>
    head>
    
    <body>
      
      <div id="root">
        <h2>人员h2>
        <input type="text" placeholder="请输入名字:" v-model="keyWord">
        <ul>
          <li v-for="(p,index) in filPersons" :key="index">
            {{p.name}}-{{p.age}}-{{p.sex}}
          li>
        ul>
      div>
    body>
    
    <script type="text/javascript">
      //用watch实现
      //#region
      /*
      new Vue({
        el: '#root',
        data: {
          keyWord: '',
          persons: [
            { id: '001', name: '马冬梅', age: 18, sex: '女' },
            { id: '002', name: '周冬雨', age: 19, sex: '女' },
            { id: '003', name: '周杰伦', age: 20, sex: '男' },
            { id: '004', name: '温兆伦', age: 21, sex: '男' },
          ],
          filPersons: []
        },
        watch: {
          keyWord:{
            immediate:true,
            handler(val) {
              this.filPersons = this.persons.filter((p) => {
                return p.name.indexOf(val) !== -1
              })
            }
          }
        }
      })
      */
      //#endregion
    
    
      // 用computed实现
      new Vue({
        el: '#root',
        data: {
          keyWord: '',
          persons: [
            { id: '001', name: '马冬梅', age: 18, sex: '女' },
            { id: '002', name: '周冬雨', age: 19, sex: '女' },
            { id: '003', name: '周杰伦', age: 20, sex: '男' },
            { id: '004', name: '温兆伦', age: 21, sex: '男' },
          ]
        },
        computed:{
          filPersons(){
            return this.filPersons = this.persons.filter((p)=>{
              return p.name.indexOf(this.keyWord) !== -1
            })
          }
        }
      })
    
    script>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    在这里插入图片描述

    列表排序

    DOCTYPE html>
    <html lang="zh-CN">
    
    <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">
      <script type="text/javascript" src="./vue.js">script>
      <title>列表排序title>
    head>
    
    <body>
      
      <div id="root">
        <h2>人员h2>
        <input type="text" placeholder="请输入名字:" v-model="keyWord">
        <button @click="sortType = 2">年龄升序button>
        <button @click="sortType = 1">年龄降序button>
        <button @click="sortType = 0">原顺序button>
        <ul>
          <li v-for="(p,index) in filPersons" :key="index">
            {{p.name}}-{{p.age}}-{{p.sex}}
          li>
        ul>
      div>
    body>
    
    <script type="text/javascript">
      // 用computed实现
      new Vue({
        el: '#root',
        data: {
          keyWord: '',
          sortType:1, //0原顺序,1降序,2升序
          persons: [
            { id: '001', name: '马冬梅', age: 18, sex: '女' },
            { id: '002', name: '周冬雨', age: 30, sex: '女' },
            { id: '003', name: '周杰伦', age: 20, sex: '男' },
            { id: '004', name: '温兆伦', age: 50, sex: '男' },
          ]
        },
        computed:{
          filPersons(){
            const arr = this.persons.filter((p)=>{
              return p.name.indexOf(this.keyWord) !== -1
            })
            // 判断是否排序
            if(this.sortType){
              arr.sort((a,b)=>{
                return this.sortType == 1 ? b.age-a.age : a.age-b.age
              })
            }
            return arr
          }
        }
      })
    
    script>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    总结Vue数据监测

    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">
        <title>数据监测title>
        
        <script type="text/javascript" src="../js/vue.js">script>
    head>
    <body>
        
        <div id="root">
            <h1>用户信息h1>
     
            <button @click="student.age++">年龄加1岁button>
            <button @click="addSex">添加性别属性,默认值为男button>
            <button @click.once="addFriend">在列表首位添加一个朋友button>
            <button @click="changeFirstFriendName">修改第一个朋友的名字为赵六button>
            <button @click.once="addHobby">添加一个爱好button>
            <button @click="changeFirstHobby">修改第一个爱好为练字button>
     
            <h3>姓名:{{student.name}}h3>
            <h3>年龄:{{student.age}}h3>
            <h3 v-if="student.sex">性别:{{student.sex}}h3>
            <h3>爱好:h3>
            <ul>
                <li v-for="(h,index) in student.hobbies" :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 type="text/javascript">
        Vue.config.productionTip =  false // 阻止 vue 在启动时生成生产提示
     
        new Vue({
            el:"#root",
            data:{
                name:"振华中学林杨",
                student:{
                    name:'张三',
                    age:18,
                    hobbies:['打游戏','敲代码','打篮球'],
                    friends:[
                        {name:'李四',age:19},
                        {name:'王五',age:20}
                    ]
                }
            },
            methods:{
                addSex(){
                    Vue.set(this.student,'sex','男')
                    //this.$set(this.student,'sex','男')
                },
                addFriend(){
                    this.student.friends.unshift({name:'玉祁',age:21})
                },
                changeFirstFriendName(){
                    this.student.friends[0].name = '赵六'
                },
                addHobby(){
                    this.student.hobbies.push('听歌')
                },
                changeFirstHobby(){
                    // this.student.hobbies.splice(0,1,'练字')
                    Vue.set(this.student.hobby,0,'练字s')
                }
            }
        })
    script>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    Vue数据监测的原理

    1. Vue会监视data中所有层次的数据。

    2. 如何监测对象中的数据?
      通过setter实现监视,且要在new Vue时就传入要监测的数据。

       对象中后追加的属性,Vue默认不做响应式处理。
       如需给后添加的属性做响应式,请使用如下API:
           Vue.set(target,prpertyName/index,value)或
           vm.$set(target,prpertyName/index,value)
      
      • 1
      • 2
      • 3
      • 4
    3. 如何监测数组中的数据?
      通过包裹数组更新元素的方式实现,本质是:

       调用原生对应的方法对数组进行更新。
       重新解析模板,进而更新页面。
      
      • 1
      • 2
    4. 在Vue修改数组中的某个元素时一定要使用如下方法:
      使用API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
      Vue.set或者vm.$set

    注意:Vue.set 和 vm.$set不能给vm或vm的根数据对象添加属性

    收集表单数据

    DOCTYPE html>
    <html lang="zh-CN">
    
    <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">
      <script type="text/javascript" src="./vue.js">script>
      <title>收集表单数据title>
    head>
    
    <body>
      
      <div id="root">
        <form @submit="demo">
          账号:<input type="text" v-model.trim="userInfo.account"><br/><br/>
          密码:<input type="password" v-model="userInfo.password"><br/><br/>
          年龄:<input type="number" v-model.number="userInfo.age"><br/><br/>
          性别:
          男<input type="radio" name="sex" v-model="userInfo.sex" value="male"><input type="radio" name="sex" v-model="userInfo.sex" value="female"><br/><br/>
          爱好:
          学习<input type="checkbox" v-model="userInfo.hobby" value="study">
          打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
          吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
          <br/><br/>
          所属校区
          <select v-model="userInfo.city">
            <option value="">请选择校区option>
            <option value="beijing">北京option>
            <option value="shanghai">上海option>
            <option value="guangzhou">广州option>
            <option value="shenzhen">深圳option>
          select>
          <br/><br/>
          其他信息:
          <textarea v-model.lazy="userInfo.other">textarea>
          <br/><br/>
          <input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://www.atguigu.com">《用户协议》a>
          <button>提交button>
        form>
      div>
    body>
    
    <script type="text/javascript">
      // 用computed实现
      new Vue({
        el: '#root',
        data: {
          userInfo:{
            account:'',
         password:'',
         age:18,
         sex:'female',
         hobby:[],
         city:'beijing',
         other:'',
         agree:''
          }
        },
        methods:{
          demo(){
            console.log(JSON.stringify(this.userInfo));
          }
         
        }
      })
    
    script>
    
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    在这里插入图片描述

     收集表单数据:
     若:<input type="text"/> 则v-model收集的是value值,用户输入的就是value值
     若:<input type="radio"/> 则v-model收集的是value值,且要给标签配置value值
     若:<input type="checkbox"/>
    
    1、没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
    2、配置input的value属性:
       (1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
       (2)v-model的初始值是数组,那么收集的就是value组成的数组
    
    备注:v-model的三个修饰符:
                        lazy:失去焦点再收集数据
                        number: 输入字符串转为有效的数字
                        trim: 输入首尾空格过滤
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    过滤器

    在这里插入图片描述

    过滤器:
    定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
    语法:
    1. 注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}
    2. 使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性 = “xxx | 过滤器名”

    备注:
    1. 过滤器也可以接收额外参数,多个过滤器能够串联。
    2. 并没有改变原本的数据,是产生新的对应的数据。

    内置指令

    在这里插入图片描述

    v-bind:单向绑定解析表达式,可简写为:
    v-model:双向数据绑定
    v-for:遍历数组 / 对象 / 字符串
    v-on:绑定事件监听,可简写为@
    v-if:条件渲染(动态控制节点是否存存在)
    v-else:条件渲染(动态控制节点是否存存在)
    v-show:条件渲染 (动态控制节点是否展示)
    v-text:向其所在的节点中渲染文本内容
    与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会
    
    v-html指令:向指定节点中渲染包含html结构的内容
    与插值语法的区别:
    1. v-html会替换掉节点中所有的内容,{{xx}}则不会
    2. v-html可以识别html结构
    严重注意:v-html有安全性问题!!!在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击!!!一定要在可信的内容上使用v-html,永远不要用在用户提交的内容上!!!
    
    v-cloak指令(没有值):
    本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
    使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题
    
    v-once指令:v-once所在节点在初次动态渲染后,就视为静态内容了,以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能
    
    v-pre指令:跳过其所在节点的编译过程
    可利用它跳过没有使用指令语法、没有使用插值语法的节点,会加快编译
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    v-text

    DOCTYPE html>
    <html lang="zh-CN">
    
    <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">
      <script type="text/javascript" src="./js/vue.js">script>
      <title>v-texttitle>
    head>
    
    <body>
      
      <div id="root">
        <div>{{name}}div>
        <div v-text="name">div>
        <div v-text="str">div>
      div>
    body>
    
    <script type="text/javascript">
      new Vue({
        el: '#root',
        data: {
          name:'尚硅谷',
          str:'

    你好啊!' }, }) script> html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在这里插入图片描述

    v-html

    DOCTYPE html>
    <html lang="zh-CN">
    
    <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">
      <script type="text/javascript" src="./js/vue.js">script>
      <title>v-htmltitle>
    head>
    
    <body>
      
      <div id="root">
        <div>{{name}}div>
        <div v-html="str">div>
        <div v-html="str2">div>
    
      div>
    body>
    
    <script type="text/javascript">
      new Vue({
        el: '#root',
        data: {
          name:'尚硅谷',
          str:'

    你好啊!', str2:'August always safe!', }, }) script> html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述

    v-cloak

    DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8" />
    		<title>v-cloaktitle>
    		<style>
    			[v-cloak]{
    				display:none;
    			}
    		style>
    	head>
    	<body>
    		<div id="root">
    			<h2 v-cloak>{{name}}h2>
    		div>
    		<script type="text/javascript" src="../js/vue.js">script>
    	body>
    	
    	<script type="text/javascript">
    		Vue.config.productionTip = false
    		
    		new Vue({
    			el:'#root',
    			data:{
    				name:'尚硅谷'
    			}
    		})
    	script>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    v-once

    DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8" />
    		<title>v-oncetitle>
    	head>
    	<body>
    		<div id="root">
          <h2 v-once>初始化的n值是:{{n}}h2>
    			<h2>当前n值是:{{n}}h2>
          <button @click="n++">点我n+1button>
    		div>
    		<script type="text/javascript" src="./js/vue.js">script>
    	body>
    	
    	<script type="text/javascript">
    		Vue.config.productionTip = false
    		
    		new Vue({
    			el:'#root',
    			data:{
    				n:1
    			}
    		})
    	script>
    html>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在这里插入图片描述

    v-pre

    DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8" />
    		<title>v-pretitle>
    	head>
    	<body>
    		<div id="root">
          <h2 v-pre>Vue其实很简单h2>
    			<h2>当前n值是:{{n}}h2>
          <button @click="n++">点我n+1button>
    		div>
    		<script type="text/javascript" src="./js/vue.js">script>
    	body>
    	
    	<script type="text/javascript">
    		Vue.config.productionTip = false
    		
    		new Vue({
    			el:'#root',
    			data:{
    				n:1
    			}
    		})
    	script>
    html>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    自定义指令_函数式

    DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8" />
    		<title>自定义指令title>
    		<script type="text/javascript" src="./js/vue.js">script>
    	head>
        
    	<body>
    		<div id="root">
    			<h2>当前的n值是:<span v-text="n">span> h2>
    			<h2>放大10倍后的n值是:<span v-big="n">span> h2>
    			<button @click="n++">点我n+1button>
    			<hr/>
    			<input type="text" v-fbind:value="n">
    		div>
    	body>
    	
    	<script type="text/javascript">
    		Vue.config.productionTip = false
    
    		new Vue({
    			el:'#root',
    			data:{
    				n:1
    			},
    			directives:{
            //big函数何时会被调用?1.指令与元素成功绑定时(一上来) 2.指令所在的模板被重新解析时
    				big(element,binding){
    					console.log('big',this) //注意此处的this是window
    					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>
    html>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    在这里插入图片描述

    自定义指令定义语法:
    一、定义语法:
    (1) 局部指令:

    new Vue({ directives:{指令名:配置对象} })
    new Vue({ directives:{指令名:回调函数} })

    (2) 全局指令:
    Vue.directive(指令名,配置对象) Vue.directive(指令名,回调函数)

    二、配置对象中常用的3个回调函数:
    (1) bind(element,binding):指令与元素成功绑定时调用
    (2) inserted(element,binding):指令所在元素被插入页面时调用
    (3) update(element,binding):指令所在模板结构被重新解析时调用
    三、备注:

    1. 指令定义时不加“v-”,但使用时要加“v-”
    2. 指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名
      在这里插入图片描述

    生命周期

    在这里插入图片描述

    DOCTYPE html>
    <html lang="zh-CN">
    
    <head>
      <meta charset="UTF-8">
      <title>生命周期title>
      <script type="text/javascript" src="./js/vue.js">script>
    head>
    
    <body>
      <div id="root" :x="n">
        <h2 v-text="n">h2>
        <h2>当前的n值是:{{n}}h2>
    
        <button @click="add">点我n+1button>
        <button @click="bye">点我销毁vmbutton>
      div>
    
      <script type="text/javascript">
        Vue.config.productionTip = false
    
        new Vue({
          el: '#root',
        //   template: `
        //   
    //

    当前的n值是:{{n}}

    // //
    `,
    data: { n:1, }, methods: { add(){ console.log('add') this.n++ }, bye(){ console.log('bye') this.$destroy() } }, beforeCreate(){ console.log('beforeCreate') }, created(){ console.log('created') }, beforeMount(){ console.log('beforeMount') }, mounted(){ console.log('mounted') }, beforeUpdate(){ console.log('beforeUpdate') }, updated(){ console.log('updated') }, beforeDestroy(){ console.log('beforeDestroy') }, destroyed(){ console.log('destroyed') } })
    script> body> html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    常见生命周期钩子:
    mounted:发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
    beforeDestroy:清除定时器,解绑在定义事件、取消订阅消息等【收尾工作】。
    关于销毁Vue实例:
    1. 销毁后借助Vue开发者工具看不到任何信息。
    2. 销毁后自定义事件会失效,但原生DOM依然有效。
    3. 一般不会在beforeDestroy操作数据,因为此时操作了数据也不会再触发更新流程了。
    4. 总结:生命周期钩子共有八个,包括beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroy。

    在这里插入图片描述
    在这里插入图片描述

    Vue组件化编程

    在这里插入图片描述
    在这里插入图片描述

    非单文件组件

    在这里插入图片描述

    非单文件组件:一个文件中包含有n个组件
    单文件组件:一个文件中包含有1个组件

    DOCTYPE html>
    <html lang="zh-CN">
    
    <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">
      <title>非单文件组件title>
      <script type="text/javascript" src="./js/vue.js">script>
    head>
    
    <body>
      <div id="root">
        <h1>{{msg}}h1>
        <hr>
        
        <school>school>
        <hr>
        <student>student>
        <hello>hello>
        <hr>
      div>
    
      <div id="root2">
        <hello>hello>
      div>
    
    body>
    <script>
      // 创建school组件
      const school = Vue.extend({
        template:
          `

    学校名称:{{schoolName}}

    学校地址:{{address}}

    `
    , // el:'#root', 一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器 data() { return { schoolName: '尚硅谷', address: '广东广州' } }, methods:{ showName(){ alert(this.schoolName) } } }) // 创建student组件 const student = Vue.extend({ template: `

    学校姓名:{{studentName}}

    学校年龄:{{age}}

    `
    , data() { return { studentName: '张三', age: 18 } } }) const hello = Vue.extend({ template:`

    你哈有

    `
    , data(){ return { name:'Tom' } } }) // 全局注册 Vue.component('hello',hello) // 创建vm new Vue({ el: '#root', data: { msg: '你好呀', }, // 注册组件(局部注册) components: { school, student } }) new Vue({ el: '#root2' })
    script> html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100

    在这里插入图片描述

    Vue使用组件的三大步骤:
    一、定义组件(创建组件)
    二、注册组件
    三、使用组件(写组件标签)

    一、如何定义一个组件?
    使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但区别如下:
    (1)el不要写。因为最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器
    (2)data必须写成函数。避免组件被复用时,数据存在引用关系。
    备注:使用template可以配置组件结构
    二、如何注册组件?
    局部注册:靠new Vue的时候传入components选项
    全局注册:靠Vue,component(‘组件名’,组件)
    三、编写组件标签
    <组件名>

    注意

    1.关于组件名:
        一个单词组成:
            第一种写法(首字母小写):study
            第二种写法(首字母大写):Study
        多个单词组成:
            第一种写法(Kebab-case命名):my-study
            第二种写法(CamelCase命名):MyStudy(需要Vue脚手架支持)
        备注:
            组件名尽可能回避HTML中已有的元素名。例如:h2、H2等。
            可以使用name配置项指定组件周期开发者工具中呈现的名字。
    
    2.关于组件标签:
        第一种写法:<study><study>
        第二种写法:<study/>
        备注:不使用脚手架时,<study/>会导致后续组件不能渲染。
    
    3.一个简写方式:
        const study = Vue.extend(options) ==> const study = options
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    组件的嵌套

    DOCTYPE html>
    <html lang="zh-CN">
    
    <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">
      <title>组件嵌套title>
      <script type="text/javascript" src="./js/vue.js">script>
    head>
    
    <body>
      <div id="root">
        
        <app>app>
      div>
    body>
    
    <script>
       const student = Vue.extend({
        template:
          `

    学生姓名:{{studentName}}

    学生年龄:{{age}}

    `
    , // el:'#root', 一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器 data() { return { studentName: '晓谷', age:18 } } }) const school = Vue.extend({ template: `

    学校名称:{{schoolName}}

    学校地址:{{address}}

    `
    , data() { return { schoolName: '尚硅谷', address: '广东广州' } }, // 注册组件(局部注册) components:{ student } }) const hello = Vue.extend({ template:`

    {{msg}}

    `
    , data(){ return { msg:'欢迎来到振华中学' } } }) const app = Vue.extend({ template:`
    `
    , components:{ school, hello } }) new Vue({ el: '#root', // 注册组件(局部注册) components: { app } })
    script> html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    在这里插入图片描述

    VueComponent构造函数

    关于VueComponent:

    1. school组件本质是一个名为VueComponent的构造函数,且不是程序定义的,是Vue.extend生成的。
    2. 我们只需要写,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)
    3. 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!
    4. 关于this指向:
      (1)组件配置中:
      data函数,methods中的函数,watch中的函数,computed中的函数,它们的this均是[VueComponent实例对象]
      (2)new Vue(options)配置中:
      data函数,methods中的函数,watch中的函数,computed中的函数,它们的this均是[Vue实例对象]
    5. VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。
      Vue的实例对象,以后简称vm

    1.一个重要的内置关系:
    VueComponent.prototype.proto===Vue.protptype

    2.为什么要有这个关系:
    让组件实例对象(vc)可以访问到Vue原型上的属性,方法。

    单文件组件

    写法:

    <template>
        
    template>
    
    <script>
    // 组件交互相关的代码(数据、方法)
    script>
    
    
    <style>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Vue脚手架

    在这里插入图片描述

    项目文件在这里插入图片描述

    main.js
    // 该文件是项目入口文件
    
    // 引入Vue
    import Vue from 'vue'
    // 引入App组件,是所有组件的父组件
    import App from './App.vue'
    // 关闭Vue生产提示
    Vue.config.productionTip = false
    
    // 创建Vue实例对象——vm
    new Vue({
      // 将App组件放入容器
      render: h => h(App),
    }).$mount('#app')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    ref 与 props

    this.$ref:可以获取到真实DOM对象/组件的实例对象
    在这里插入图片描述

    ref
    **ref属性**
    1. 被用来给元素或子组件注册引用信息(id的替代者)
    2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
    3. 使用方式:
    打标识:<h1 ref="xxx">.....</h1><School ref="xxx"></School>
    获取:this.$refs.xxx
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    <template>
      <div>
        <h1 v-text="msg" ref="title">h1>
        <button ref="btn" @click="showDOM">点我输出上方dom元素button>
        <School ref="sch">School>
      div>
    template>
      
    <script>
    // 引入组件
    import School from './components/School.vue'
    export default {
      name: 'App',
      data(){
        return {
          msg: '欢迎学习Vue'
        }
      },
      components: {
          School
      },
      methods: {
        showDOM(){
          console.log(this.$refs.title) //真实dom元素
          console.log(this.$refs.btn) //真实dom元素
          console.log(this.$refs.sch) //School组建的实例对象vc
        }
      }
    }
    
    script>
      
    <style>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述

    props

    功能:让组件接收外部传过来的数据

    传递数据:

    接收数据:

    第一种方式(只接收):props:[‘name’]

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

    第三种方式(限制类型、限制必要性、指定默认值):
    props:{
    name:{
    type:String, //类型
    required:true, //必要性
    default:‘老王’ //默认值
    }
    }

    备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

    <template>
        
        <div class="demo">
            <h1>{{ msg }}h1>
            <h2>学生姓名:{{ studentName }}h2>
            <h2>学生性别:{{ sex }}h2>
            <h2>学生年龄:{{ myAge + 1 }}h2>
            <button @click="updateAge">尝试修改收到的年龄button>
        div>
    template>
    
    <script>
    // 组件交互相关的代码(数据、方法)
    export default {
        name: 'Student',
        data() {
            console.log(this)
            return {
                msg: '我是振华中学学生!',
                myAge:this.age
            }
        },
        methods: {
            updateAge(){
                this.myAge++
            }
        },
        // 简单接受
        // props:['studentName,'age','sex']
        /*
        props:{
            studentName:String,
            age:Number,
            sex:String
        }
        */
    
        // 接收时同时对数据进行类型限制+默认值的制定+必要性的限制
        props: {
            studentName: {
                type: String,
                required: true
            },
            age: {
                type: Number,
                default: 99
            },
            sex: {
                type: String,
                required: true
            }
        }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    在这里插入图片描述

    混入mixin

    在这里插入图片描述在这里插入图片描述

    功能:可以把多个组件共用的配置提取成一个混入对象

    使用方式:

    第一步,定义混合:

    {
        data(){....},
        methods:{....}
        ....
    }
    
    export const hunhe = {
    	methods: {
    		showName(){
    			alert(this.name)
    		}
    	},
    	mounted() {
    		console.log('你好啊!')
    	},
    }
    export const hunhe2 = {
    	data() {
    		return {
    			x:100,
    			y:200
    		}
    	},
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    第二步,使用混入:

    全局混入:Vue.mixin(xxx)
    局部混入:mixins:[‘xxx’]

    插件

    在这里插入图片描述
    功能:用于增强Vue

    本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。

    定义插件:

    对象.install = function (Vue, options) {
        // 1. 添加全局过滤器
        Vue.filter(....)
    
        // 2. 添加全局指令
        Vue.directive(....)
    
        // 3. 配置全局混入(合)
        Vue.mixin(....)
    
        // 4. 添加实例方法
        Vue.prototype.$myMethod = function () {...}
        Vue.prototype.$myProperty = xxxx
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    使用插件:Vue.use()

    export default {
        install(Vue,x,y,z) {
            console.log(x,y,z);
            //全局过滤器
            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:200
                   }
                },
             })
       
             //给Vue原型上添加一个方法(vm和vc就都能用了)
             Vue.prototype.hello = ()=>{alert('你好啊')}
        }
    }
           Vue.prototype.hello = ()=>{alert('你好啊')}
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    在这里插入图片描述

    scoped样式

    作用:让样式在局部生效,防止冲突
    写法:< style scoped >

    Todolist案例

    在这里插入图片描述

    静态组件

    Item.vue

    <template>
        <li>
            <label>
                <input type="checkbox" />
                <span>xxxxx</span>
            </label>
            <button class="btn btn-danger" style="display:none">删除</button>
        </li>
    </template>
    
    <script>
    export default {
        name: 'Item',
    
    }
    </script>
    
    <style scoped>
     
      /*item*/
      li {
        list-style: none;
        height: 36px;
        line-height: 36px;
        padding: 0 5px;
        border-bottom: 1px solid #ddd;
      }
      
      li label {
        float: left;
        cursor: pointer;
      }
      
      li label li input {
        vertical-align: middle;
        margin-right: 6px;
        position: relative;
        top: -1px;
      }
      
      li button {
        float: right;
        display: none;
        margin-top: 3px;
      }
      
      li:before {
        content: initial;
      }
      
      li:last-child {
        border-bottom: none;
      }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    List.vue

    <template>
        <ul class="todo-main">
            <Item></Item>
            <Item></Item>
            <Item></Item>
            <Item></Item>
        </ul>
    </template>
    
    <script>
    import Item from '../components/Item.vue'
    export default {
        name: 'List',
        components: { Item },
    
    
    }
    </script>
    
    
    <style scoped>
    /*main*/
    .todo-main {
        margin-left: 0px;
        border: 1px solid #ddd;
        border-radius: 2px;
        padding: 0px;
      }
      
      .todo-empty {
        height: 40px;
        line-height: 40px;
        border: 1px solid #ddd;
        border-radius: 2px;
        padding-left: 5px;
        margin-top: 10px;
      }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    MyFooter.vue

    <template>
        <div class="todo-footer">
            <label>
                <input type="checkbox" />
            </label>
            <span>
                <span>已完成0</span> / 全部2
            </span>
            <button class="btn btn-danger">清除已完成任务</button>
        </div>
    </template>
    
    <script>
    export default {
        name: 'MyFooter',
    
    }
    </script>
    
    <style scoped>
    
    
    /*footer*/
    .todo-footer {
        height: 40px;
        line-height: 40px;
        padding-left: 6px;
        margin-top: 5px;
      }
      
      .todo-footer label {
        display: inline-block;
        margin-right: 20px;
        cursor: pointer;
      }
      
      .todo-footer label input {
        position: relative;
        top: -1px;
        vertical-align: middle;
        margin-right: 5px;
      }
      
      .todo-footer button {
        float: right;
        margin-top: 5px;
      }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    MyHeader.vue

    <template>
        <div class="todo-header">
            <input type="text" placeholder="请输入你的任务名称,按回车键确认" />
          </div>
    </template>
    
    <script>
    export default {
        name: 'MyHeader',
    
    }
    </script>
    
    <style scoped>
    /*header*/
    .todo-header input {
        width: 560px;
        height: 28px;
        font-size: 14px;
        border: 1px solid #ccc;
        border-radius: 4px;
        padding: 4px 7px;
      }
      
      .todo-header input:focus {
        outline: none;
        border-color: rgba(82, 168, 236, 0.8);
        box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
      }  
      
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    App.vue

    <template>
      <div id="root">
        <div class="todo-container">
          <div class="todo-wrap">
            <MyHeader></MyHeader>
            <List></List>
            <MyFooter></MyFooter>
          </div>
        </div>
      </div>
    </template>
      
    <script>
    // 引入组件
    import MyHeader from './components/MyHeader.vue'
    import List from './components/List.vue'
    import MyFooter from './components/MyFooter.vue'
    
    export default {
      name: 'App',
      components: {
        MyHeader,
        List,
        MyFooter
      }
    }
    </script>
    
    <style>
    /*base*/
    body {
      background: #fff;
    }
    
    .btn {
      display: inline-block;
      padding: 4px 12px;
      margin-bottom: 0;
      font-size: 14px;
      line-height: 20px;
      text-align: center;
      vertical-align: middle;
      cursor: pointer;
      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
      border-radius: 4px;
    }
    
    .btn-danger {
      color: #fff;
      background-color: #da4f49;
      border: 1px solid #bd362f;
    }
    
    .btn-danger:hover {
      color: #fff;
      background-color: #bd362f;
    }
    
    .btn:focus {
      outline: none;
    }
    
    .todo-container {
      width: 600px;
      margin: 0 auto;
    }
    
    .todo-container .todo-wrap {
      padding: 10px;
      border: 1px solid #ddd;
      border-radius: 5px;
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    在这里插入图片描述

    展示动态数据

    在这里插入图片描述

    TodoList.vue

    <template>
      <div>
        <ul class="todo-main">
          <TodoItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj"></TodoItem>
        </ul>
      </div>
    </template>
    
    <script>
    import TodoItem from "@/components/TodoItem";
    
    export default {
      name: "TodoList",
      components:{
        TodoItem
      },
      data(){
        return {
          todos:[
            {id:'001',title:'ielts',done:true},
            {id:'002',title:'meal',done:true},
            {id:'003',title:'Vue',done:true}
          ]
        }
      }
    }
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    TodoItem.vue

    <template>
        <li>
        <label>
          <input type="checkbox" :checked="false"/>
          <span>{{todo.title}}</span>
        </label>
        <button class="btn btn-danger" style="display:none">删除</button>
      </li>
    </template>
    
    <script>
    export default {
      name: "TodoItem",
      //接收todo对象
      props:['todo'],
    }
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    TodoHeader.vue

    <template>
      <div class="todo-header">
        <input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title"  @keyup.enter="add"/>
      </div>
    </template>
    
    <script>
    import {nanoid} from 'nanoid' //需安装  npm i nanoid
    export default {
      props:['addTodo'], //父亲给儿子传一个函数
      name: "TodoHeader",
      data(){
        return {title: ''}
      },
      methods:{
        add(){
          if (this.title.trim() ===''){  return alert("不能输入空值"); }
          // const text =  event.target.value; //通过传入事件对象获取
          const todoObj = {id:nanoid(),title:this.title,done:false};
          this.addTodo(todoObj); //儿子调用传递参数
          this.title='';//输入完之后清空
          // event.target.value=''; //输入完之后清空
        }
      }
    }
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    删除

    显示删除按钮

    <!--去掉display-->
    <button class="btn btn-danger" >删除</button>
    
    <style scoped>
        /*添加选中变灰*/
        li:hover{
          background-color: #cccccc;
        }
        li:hover button{
          display: block;
        }
    </style>
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    App.vue

    <TodoList :todos="todos" :updateTodo="updateTodo" :deleteTodo="deleteTodo"></TodoList>
    
    deleteTodo(id){
        this.todos = this.todos.filter((todo)=>{
          return todo.id !==id
        })
      // this.todos = this.todos.filter( todo=> todo.id !==id) //简写
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    TodoList.vue

    <TodoItem v-for="todoObj in todos"
              :key="todoObj.id" :todo="todoObj"
              :updateTodo="updateTodo"
              :deleteTodo="deleteTodo"></TodoItem>
    props:['todos','updateTodo','deleteTodo'],
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    TodoItem.vue

    <button class="btn btn-danger"  @click="deleteItem(todo.id)">删除</button>
    
        props:['todo','updateTodo','deleteTodo'],
        methods:{
        deleteItem(id){
          if (confirm('确定删除?')){ //点确定为真, 取消为假
            this.deleteTodo(id);
          }
        }
      }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    底部统计

    App.vue, App传todos到footer

    <TodoFooter :todos="todos"></TodoFooter>
    
    
    • 1
    • 2

    TodoFooter.vue

    <template>
        <div class="todo-footer">
          <label>
            <input type="checkbox"/>
          </label>
          <span>
              <span>已完成{{todoCount}}</span> / 全部{{todos.length}}
            </span>
          <button class="btn btn-danger">清除已完成任务</button>
        </div>
    </template>
    
    <script>
    export default {
      props:['todos'],
      name: "TodoFooter",
      computed:{
        todoCount(){
          return  this.todos.reduce((pre,todo)=>{
              return pre + (todo.done ? 1 : 0); //如果勾选了就+1
          },0)
          //      this.todos.reduce((pre,todo) => pre + (todo.done ? 1 : 0),0) //简写
    /*   forEach方式
          let i = 0;
          this.todos.forEach((todo)=>{
            if (todo.done){
              i++
            }
          });
          return i;*/
    
    /*      filter方法
              return  this.todos.filter((todo)=>{
              return todo.done !== false;
          }).length*/
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    reduce方法

      this.todos.reduce((pre,todo)=>{
          return pre + (todo.done ? 1 : 0); //如果勾选了就+1
      },0)
      //      this.todos.reduce((pre,todo) => pre + (todo.done ? 1 : 0),0) //简写
      /*
         this.todos.reduce((pre,current)=>{},n) ,
         调用次数= 数组长度
         pre : 上一次调用函数的返回值
         current:  数组里的每个对象, 这是是todo
         n:统计的初始值
       */
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    底部交互

    App.vue

    <template>
     <div>
        <div id="root">
          <div class="todo-container">
            <div class="todo-wrap">
              <TdHeader :addTodo="addTodo"></TdHeader>
            <!--  传递给item需要通过list传        -->
              <TodoList :todos="todos" :updateTodo="updateTodo" :deleteTodo="deleteTodo"></TodoList>
              <TodoFooter :todos="todos" :isAllTotal="isAllTotal" :clearAllTodo="clearAllTodo"></TodoFooter>
            </div>
          </div>
        </div>
    
      </div>
    </template>
    
    <script>
     //引入组件
      import TodoFooter from "@/components/TodoFooter";
      import TdHeader from "@/components/TodoHeader";
      import TodoList from "@/components/TodoList";
     export default {
      name:'App',
      components:{
          TdHeader,TodoList,TodoFooter
      },
        data() {
          return {
            todos: [
              {id: '001', title: '吃饭', done: false},
              {id: '002', title: '睡觉', done: true},
              {id: '003', title: '开车', done: true}
            ]
          }
        },
        methods:{
          //添加待办项
          addTodo(todoObj){ //接收儿子传递的参数
            this.todos.unshift(todoObj);
          },
          //修改待办项状态, done
          updateTodo(id){
              this.todos.forEach((todo)=>{
                  if (todo.id === id){
                    todo.done = !todo.done;
                  }
              });
          },
          //删除待办项
          deleteTodo(id){
              this.todos = this.todos.filter((todo)=>{
                return todo.id !==id
              })
            // this.todos = this.todos.filter( todo=> todo.id !==id) //简写
          },
          //修改待办项状态
          isAllTotal(done){
            this.todos.forEach((todo)=>{
              todo.done = done
            })
          },
          //清除已完成的事项
          clearAllTodo(){
            this.todos = this.todos.filter((todo)=>{
              return !todo.done
            })
          }
        }
     }
    
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    TodoFooter.vue

    <template>
        <div class="todo-footer" v-show="total">
          <label>
            <input type="checkbox" v-model="isAll"/>
          </label>
          <span>
              <span>已完成{{todoCount}}</span> / 全部{{total}}
            </span>
          <button class="btn btn-danger" @click="clearTodo">清除已完成任务</button>
        </div>
    </template>
    
    <script>
    export default {
      props:['todos','isAllTotal','clearAllTodo'],
      name: "TodoFooter",
      computed:{
        total(){
          return this.todos.length
        },
        isAll:{
          get(){
            return this.todoCount === this.total && this.total >0;
          },
          set(value){
            this.isAllTotal(value)
          }
        },
        todoCount(){
          return  this.todos.reduce((pre,todo)=>{
              return pre + (todo.done ? 1 : 0); //如果勾选了就+1
          },0)
          //      this.todos.reduce((pre,todo) => pre + (todo.done ? 1 : 0),0) //简写
          /*
             this.todos.reduce((pre,current)=>{},n) ,
             调用次数= 数组长度
             pre : 上一次调用函数的返回值
             current:  数组里的每个对象, 这是是todo
             n:统计的初始值
           */
    /*   forEach方式
          let i = 0;
          this.todos.forEach((todo)=>{
            if (todo.done){
              i++
            }
          });
          return i;*/
    
    /*      filter方法
              return  this.todos.filter((todo)=>{
              return todo.done !== false;
          }).length*/
        }
      },
      methods:{
        clearTodo(){
          if (this.todoCount<=0){ //没有勾选就不执行
            return
          }
          if (confirm('是否清除?')){
            this.clearAllTodo();
          }
        }
      }
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    总结TodoList案例

    1. 组件化编码流程:

    ​ (1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。

    ​ (2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:

    ​ (1).一个组件在用:放在组件自身即可。
    ​ (2). 一些组件在用:放在他们共同的父组件上(状态提升)。
    ​ (3).实现交互:从绑定事件开始。

    1. props适用于:

    ​ (1).父组件 ==> 子组件 通信

    ​ (2).子组件 ==> 父组件 通信(要求父先给子一个函数)

    1. 使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!

    2. props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。

    浏览器本地存储

    localStroage

    <!DOCTYPE html>
    <html lang="zh-CN">
    <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">
        <title>localStorage</title>
    </head>
    <body>
        <h2>localStorage</h2>
        <button onclick="saveData()">点我保存数据</button>
        <button onclick="readData()">点我读取数据</button>
        <button onclick="deleteData()">点我删除数据</button>
        <button onclick="deleteAllData()">点我全部删除数据</button>
        
    
        <script type="text/javascript">
            let p = {name:'zs',age:18}
            function saveData(){
                localStorage.setItem('msg','hello')
                localStorage.setItem('msg2',666)
                localStorage.setItem('person',JSON.stringify(p))
            }
            function readData(){
                console.log(localStorage.getItem('msg'))
                console.log(localStorage.getItem('msg2'))
                const result= localStorage.getItem('person')
                console.log(JSON.parse(result))
            }
            function deleteData(){
                localStorage.removeItem('msg')
            }
            function deleteAllData(){
                localStorage.clear()
            }
            
        </script>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    在这里插入图片描述
    浏览器关闭数据仍不会消失,5M容量, 一直存在, 除非用户清空缓存, 或调用api清除
    sessionStorage

    <!DOCTYPE html>
    <html lang="zh-CN">
    <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">
        <title>sessionStorage</title>
    </head>
    <body>
        <h2>sessionStorage</h2>
        <button onclick="saveData()">点我保存数据</button>
        <button onclick="readData()">点我读取数据</button>
        <button onclick="deleteData()">点我删除数据</button>
        <button onclick="deleteAllData()">点我全部删除数据</button>
        
    
        <script type="text/javascript">
            let p = {name:'zs',age:18}
            function saveData(){
                sessionStorage.setItem('msg','hello')
                sessionStorage.setItem('msg2',666)
                sessionStorage.setItem('person',JSON.stringify(p))
            }
            function readData(){
                console.log(sessionStorage.getItem('msg'))
                console.log(sessionStorage.getItem('msg2'))
                const result= sessionStorage.getItem('person')
                console.log(JSON.parse(result))
            }
            function deleteData(){
                sessionStorage.removeItem('msg')
            }
            function deleteAllData(){
                sessionStorage.clear()
            }
            
        </script>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    会话结束就清空, 关闭浏览器清空

    webStorage

    1. 存储内容大小一般支持5MB左右(不同浏览器可能还不一样)
    2. 浏览器端通过 Window.sessionStorage 和 Window.localStorage 属性来实现本地存储机制。
    3. 相关API:
      (1)xxxxxStorage.setItem(‘key’, ‘value’); 该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。
      (2)xxxxxStorage.getItem(‘person’); ​ 该方法接受一个键名作为参数,返回键名对应的值。
      (3)xxxxxStorage.removeItem(‘key’); ​ 该方法接受一个键名作为参数,并把该键名从存储中删除。
      (4)xxxxxStorage.clear() ​ 该方法会清空存储中的所有数据。

    备注:

    1. SessionStorage存储的内容会随着浏览器窗口关闭而消失。
    2. LocalStorage存储的内容,需要手动清除才会消失。
    3. xxxxxStorage.getItem(xxx)如果xxx对应的value获取不到,那么getItem的返回值是null。
    4. JSON.parse(null)的结果依然是null。

    将Todo案例改成浏览器存储

    <script>
     export default {
      name:'App',
      components:{
     	},
        data() {
          return {
            todos: JSON.parse(localStorage.getItem('todos')) || []  //到浏览器查找, 找不到为空数组[]
          }
        },
        methods:{
          //添加待办项
        },
        watch:{
          todos:{
            deep:true,//开启深度检测, 不然发现不了done改变
            handler(newValue){
              localStorage.setItem('todos',JSON.stringify(newValue));//检测到有修改就把新的todos更新到localStorage
    /*          if (this.todos.length<=0){
                localStorage.removeItem('todos')
              }*/
            }
          }
        }
     }
    
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    组件自定义事件

    在这里插入图片描述

    绑定自定义事件

    School.vue

    <template>
        <div class="school">
            <h2>学校名称:{{name}}</h2>
            <h2>学校地址:{{address}}</h2>  
            <button @click="sendSchoolName">把学校名给App</button>   
        </div>
    </template>
    
    <script>
    export default {
        name:'School',
        props:['getSchoolName'],
        data(){
            return {
                name:'尚硅谷',
                address:'广州'
            }
        },
        methods:{
            sendSchoolName(){
                this.getSchoolName(this.name)
            }
        }
    }
    </script>
    
    <style scoped>
        .school {
            background-color: skyblue;
            padding: 5px;
        }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    Student.vue

    <template>
        <div class="student">
            <h2>学生姓名:{{name}}</h2>
            <h2>学生年龄:{{age}}</h2> 
            <button @click="sendStudentName">把学生名给App</button>    
        </div>
    </template>
    
    <script>
    export default {
        name:'Student',
        data(){
            return {
                name:'余周周',
                age:18
            }
        },
        methods:{
            sendStudentName(){
                // 触发Student组件实例身上的atguigu事件
                this.$emit('atguigu',this.name,666,888,900)
            }
        }
    }
    </script>
    
    <style scoped>
        .student {
            background-color: orange;
            padding: 5px;
            margin-top: 30px;
        }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    App.vue

    <template>
      <div class="app">
        <h1>{{ msg }}</h1>
        <!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
        <School :getSchoolName="getSchoolName"/>
        <!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法:使用@/v-on) -->
        <Student @atguigu.once="getStudentName"/>
    
        <!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法:使用ref) -->
        <!-- <Student ref="student"/> -->
      </div>
    </template>
      
    <script>
    // 引入组件
    import School from './components/School.vue'
    import Student from './components/Student.vue'
    
    export default {
      name: 'App',
      components: {
        School,
        Student
      },
      data() {
        return {
          msg: '你好呀'
        }
      },
      methods: {
        getSchoolName(name){
          console.log('App收到了学校名:',name)
        },
        getStudentName(name,...params){
          console.log('App收到了学生名:',name,params)
        }
      },
      mounted(){
        setTimeout(()=>{
          // this.$refs.student.$on('atguigu',this.getStudentName)
          // this.$refs.student.$once('atguigu',this.getStudentName)//只触发一次
        },3000)
      }
    }
    </script>
    
    <style>
    .app {
      background-color: gray;
      padding: 5px;
    }
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    在这里插入图片描述

    解绑自定义事件

    Student.vue

    <template>
        <div class="student">
            <h2>学生姓名:{{name}}</h2>
            <h2>学生年龄:{{age}}</h2> 
            <button @click="sendStudentName">把学生名给App</button>    
            <button @click="unbind">解绑atguigu事件</button>
        </div>
    </template>
    
    <script>
    export default {
        name:'Student',
        data(){
            return {
                name:'余周周',
                age:18
            }
        },
        methods:{
            sendStudentName(){
                // 触发Student组件实例身上的atguigu事件
                this.$emit('atguigu',this.name,666,888,900)
                this.$emit('demo')
    
            },
            unbind(){
                // 解绑一个自定义事件
                // this.$off('atguigu')
                // 解绑多个自定义事件
                // this.$off(['atguigu','demo'])
                // 所有自定义事件都被解绑
                this.$off()
    
            }
        }
    }
    </script>
    
    <style scoped>
        .student {
            background-color: orange;
            padding: 5px;
            margin-top: 30px;
        }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    App.vue

    <template>
      <div class="app">
        <h1>{{ msg }}</h1>
        <!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
        <School :getSchoolName="getSchoolName"/>
        <!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法:使用@/v-on) -->
        <Student @atguigu.once="getStudentName" @demo="m1"/>
    
        <!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法:使用ref) -->
        <!-- <Student ref="student"/> -->
      </div>
    </template>
      
    <script>
    // 引入组件
    import School from './components/School.vue'
    import Student from './components/Student.vue'
    
    export default {
      name: 'App',
      components: {
        School,
        Student
      },
      data() {
        return {
          msg: '你好呀'
        }
      },
      methods: {
        getSchoolName(name){
          console.log('App收到了学校名:',name)
        },
        getStudentName(name,...params){
          console.log('App收到了学生名:',name,params)
        },
        m1(){
          console.log('demo事件被触发了');
        }
      },
      mounted(){
        setTimeout(()=>{
          // this.$refs.student.$on('atguigu',this.getStudentName)
          // this.$refs.student.$once('atguigu',this.getStudentName)//只触发一次
        },3000)
      }
    }
    </script>
    
    <style>
    .app {
      background-color: gray;
      padding: 5px;
    }
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    1. 一种组件间通信的方式,适用于:子组件 ===> 父组件

    2. 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。

    3. 绑定自定义事件:
      第一种方式,在父组件中:
      第二种方式,在父组件中:

    <Demo ref="demo"/>
    ......
    mounted(){
       this.$refs.xxx.$on('atguigu',this.test)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。

    1. 触发自定义事件:this.$emit('atguigu',数据)

    2. 解绑自定义事件this.$off('atguigu')

    3. 组件上也可以绑定原生DOM事件,需要使用native修饰符。

    4. 注意:通过this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!

    全局事件总线

    全局事件总线是一种可以在任意组件间通信的方式,本质上就是一个对象。它必须满足以下条件:

    1. 所有的组件对象都必须能看见他
    2. 这个对象必须能够使用 o n 、 on、 onemit和$off方法去绑定、触发和解绑事件

    在这里插入图片描述
    在这里插入图片描述

    全局事件总线(GlobalEventBus):

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

    2. 安装全局事件总线:

    new Vue({
       	...
       	beforeCreate() {
       		Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
       	},
        ...
    }) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 使用事件总线:

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

    export default {
        methods(){
            demo(data){...}
        }
        ...
        mounted() {
            this.$bus.$on('xxx',this.demo)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 提供数据:this.$bus.$emit('xxx',data)

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

    在这里插入图片描述

    消息订阅与发布

    在这里插入图片描述
    School.vue

    <template>
        <div class="school">
            <h2>学校名称:{{name}}</h2>
            <h2>学校地址:{{address}}</h2>  
        </div>
    </template>
    
    <script>
    import pubsub from 'pubsub-js'
    export default {
        name:'School',
        props:['getSchoolName'],
        data(){
            return {
                name:'尚硅谷',
                address:'广州'
            }
        },
        methods:{
            demo(msgName,data){
                console.log('hello消息收到了',data)
            }
        },
        mounted(){
            // console.log('School',this)
            // this.$bus.$on('hello',(data)=>{
            //     console.log('School组件',data)
            // })
            this.pubId = pubsub.subscribe('hello',function(msgName,data){
                console.log('有人发布了hello消息',msgName,data);
            })
        },
        beforeDestroy(){
            // this.$bus.$off('hello')
            pubsub.unsubscribe(this.pubId)
        },
    }
    </script>
    
    <style scoped>
        .school {
            background-color: skyblue;
            padding: 5px;
        }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    Student.vue

    <template>
        <div class="student">
            <h2>学生姓名:{{name}}</h2>
            <h2>学生年龄:{{age}}</h2>
            <button @click="sendStudentName">吧学生名给School组件</button> 
        </div>
    </template>
    
    <script>
    import pubsub from 'pubsub-js'
    export default {
        name:'Student',
        data(){
            return {
                name:'余周周',
                age:18
            }
        },
        mounted(){
    
        },
        methods:{
            sendStudentName(){
                // this.$bus.$emit('hello',this.name)
                pubsub.publish('hello',666)
            }
        }
    }
    </script>
    
    <style scoped>
        .student {
            background-color: orange;
            padding: 5px;
            margin-top: 30px;
        }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    在这里插入图片描述

    消息订阅与发布(pubsub):

    消息订阅与发布是一种组件间通信的方式,适用于任意组件间通信

    使用步骤:

    安装pubsub:npm i pubsub-js

    引入:import pubsub from 'pubsub-js'

    接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身

    export default {
        methods(){
            demo(data){...}
        }
        ...
        mounted() {
    		this.pid = pubsub.subscribe('xxx',this.demo)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    提供数据:pubsub.publish('xxx',data)

    最好在beforeDestroy钩子中,使用pubsub.unsubscribe(pid)取消订阅

    nextTick
    == $nextTick(回调函数)可以将回调延迟到下次 DOM 更新循环之后执行==

    $nextTick:

    1. 语法:this.$nextTick(回调函数)
    2. 作用:在下一次 DOM 更新结束后执行其指定的回调
    3. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行

    过度与动画

    <template>
        <div>
            <button @click="isShow = !isShow">显示/隐藏</button>
            <transition name="hello" appear>
                <h1 v-show="isShow">hello</h1>
            </transition>
        </div>
    </template>
    
    <script>
    export default {
        name:'Test',
        data(){
            return {
                isShow:true
            }
        }
    }
    </script>
    
    <style scoped>
        h1 {
            background-color: orange;
        }
        .hello-enter-active {
            animation: atguigu 1s;
        }
        .hello-leave-active {
            animation: atguigu 1s reverse;
        }
        @keyframes atguigu {
            from{
                transform: translateX(-100px);
            }
            to{
                transform: translateX(0px);
            }   
        }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    在这里插入图片描述

    <template>
        <div>
            <button @click="isShow = !isShow">显示/隐藏</button>
            <transition name="hello" appear>
                <h1 v-show="isShow">hello</h1>
            </transition>
        </div>
    </template>
    
    <script>
    export default {
        name:'Test',
        data(){
            return {
                isShow:true
            }
        }
    }
    </script>
    
    <style scoped>
        h1 {
            background-color: orange;
            transition: 0.5s linear;
        }
        /*进入的起点*/
        .hello-enter {
            transform: translateX(-100%);
        }
        /*进入的终点*/
        .hello-enter-to {
            transform: translateX(0);
        }
        /*离开的起点*/
        .hello-leave {
            transform: translateX(0);
        }
        /*离开的终点*/
        .hello-leave-to {
            transform: translateX(-100%);
        }
    
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    在这里插入图片描述在这里插入图片描述

    <template>
        <div>
            <button @click="isShow = !isShow">显示/隐藏</button>
            <transition-group name="hello" appear>
                <h1 v-show="!isShow" key="1">hello</h1>
                <h1 v-show="isShow" key="2">hello111111</h1>
            </transition-group>
        </div>
    </template>
    
    <script>
    export default {
        name:'Test',
        data(){
            return {
                isShow:true
            }
        }
    }
    </script>
    
    <style scoped>
        h1 {
            background-color: orange;
            transition: 0.5s linear;
        }
        /*进入的起点*/
        .hello-enter {
            transform: translateX(-100%);
        }
        /*进入的终点*/
        .hello-enter-to {
            transform: translateX(0);
        }
        /*离开的起点*/
        .hello-leave {
            transform: translateX(0);
        }
        /*离开的终点*/
        .hello-leave-to {
            transform: translateX(-100%);
        }
    
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    在这里插入图片描述
    Vue封装的过度与动画:

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

    1. 准备好样式:

    (1)元素进入的样式:

    v-enter:进入的起点
    v-enter-active:进入过程中
    v-enter-to:进入的终点
    (2)元素离开的样式:

    v-leave:离开的起点
    v-leave-active:离开过程中
    v-leave-to:离开的终点
    2. 使用包裹要过度的元素,并配置name属性:

    <transition name="hello">
    	<h1 v-show="isShow">你好啊!</h1>
    </transition>
    
    • 1
    • 2
    • 3
    1. 备注:若有多个元素需要过度,则需要使用:,且每个元素都要指定key值

    配置代理

    在这里插入图片描述
    方法一:只能配置一个代理,不能控制灵活控制代理
    App.vue

    <template>
      <div>
        <button @click="getStudents">获取学生信息</button>
      </div>
    </template>
      
    <script>
    import axios from 'axios'
    export default {
      name: 'App',
      methods: {
        getStudents(){
          axios.get('http://localhost:8080/students').then(
            response => {
              console.log('请求成功了',response.data)
            },
            error => {
              console.log('请求失败了',error.message)
            }
          )
        }
      }
    }
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    vue.config.js

    const { defineConfig } = require('@vue/cli-service')
    module.exports = defineConfig({
      transpileDependencies: true,
      pages: {
        index: {
          // 入口
          entry: 'src/main.js'
        }
      },
      //关闭语法检查
      lintOnSave:false,  
      // 开启代理服务器
      devServer: {
        proxy: 'http://localhost:5000'
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述
    方法二:
    App.vue

    <template>
      <div>
        <button @click="getStudents">获取学生信息</button>
        <button @click="getCars">获取汽车信息</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/cars').then(
            response => {
              console.log('请求成功了',response.data)
            },
            error => {
              console.log('请求失败了',error.message)
            }
          )
        }
      }
    }
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    vue.config.js

    const { defineConfig } = require('@vue/cli-service')
    module.exports = defineConfig({
      transpileDependencies: true,
      pages: {
        index: {
          // 入口
          entry: 'src/main.js'
        }
      },
      //关闭语法检查
      lintOnSave:false,  
      // 开启代理服务器(方式一)
      /*devServer: {
        proxy: 'http://localhost:5000'
      }*/
    
        // 开启代理服务器(方式二)
        devServer: {
          proxy: {
            '/atguigu':{
              target: 'http://localhost:5000',
              pathRewrite: {'^/atguigu':''},
              ws: true, //用于支持websocket
              changeOrigin: true
            },
            '/demo':{
              target: 'http://localhost:5001',
              pathRewrite: {'^/demo':''},
              ws: true, //用于支持websocket
              changeOrigin: true
            }
          }
        }
    
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    在这里插入图片描述
    vue脚手架配置代理服务器:

    方法一:在vue.config.js中添加如下配置:

    devServer:{
        proxy:"http://localhost:5000"
    }
    
    • 1
    • 2
    • 3

    说明:

    1. 优点:配置简单,请求资源时直接发给前端即可
    2. 缺点:不能配置多个代理,不能灵活的控制请求是否走代理
    3. 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)

    方法二:

    devServer: {
        proxy: {
          	'/api1': { // 匹配所有以 '/api1'开头的请求路径
            	target: 'http://localhost:5000',// 代理目标的基础路径
            	changeOrigin: true,
            	pathRewrite: {'^/api1': ''}
          	},
          	'/api2': { // 匹配所有以 '/api2'开头的请求路径
            	target: 'http://localhost:5001',// 代理目标的基础路径
            	changeOrigin: true,
            	pathRewrite: {'^/api2': ''}
          	}
        }
    }
    
    // changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
    // changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    说明:

    1. 优点:可以配置多个代理,且可以灵活的控制请求是否走代理
    2. 缺点:配置略微繁琐,请求资源时必须加前缀

    vue-resource

    在这里插入图片描述

    slot插槽

    在这里插入图片描述

    默认插槽

    App.vue

    <template>
    	<div class="container">
    		<Category title="美食" >
    			<img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
    		</Category>
    
    		<Category title="游戏" >
    			<ul>
    				<li v-for="(g,index) in games" :key="index">{{g}}</li>
    			</ul>
    		</Category>
    
    		<Category title="电影">
    			<video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
    		</Category>
    	</div>
    </template>
    
    <script>
    	import Category from './components/Category'
    	export default {
    		name:'App',
    		components:{Category},
    		data() {
    			return {
    				games:['植物大战僵尸','红色警戒','空洞骑士','王国']
    			}
    		},
    	}
    </script>
    
    <style scoped>
    	.container{
    		display: flex;
    		justify-content: space-around;
    	}
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    Category.vue

    <template>
    	<div class="category">
    		<h3>{{title}}分类</h3>
    		<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
    		<slot>我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'Category',
    		props:['title']
    	}
    </script>
    
    <style scoped>
    	.category{
    		background-color: skyblue;
    		width: 200px;
    		height: 300px;
    	}
    	h3{
    		text-align: center;
    		background-color: orange;
    	}
    	video{
    		width: 100%;
    	}
    	img{
    		width: 100%;
    	}
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    具名插槽

    App.vue*

    <template>
    	<div class="container">
    		<Category title="美食" >
    			<img slot="center" src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
    			<a slot="footer" href="http://www.atguigu.com">更多美食</a>
    		</Category>
    
    		<Category title="游戏" >
    			<ul slot="center">
    				<li v-for="(g,index) in games" :key="index">{{g}}</li>
    			</ul>
    			<div class="foot" slot="footer">
    				<a href="http://www.atguigu.com">单机游戏</a>
    				<a href="http://www.atguigu.com">网络游戏</a>
    			</div>
    		</Category>
    
    		<Category title="电影">
    			<video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
    			<template v-slot:footer>
    				<div class="foot">
    					<a href="http://www.atguigu.com">经典</a>
    					<a href="http://www.atguigu.com">热门</a>
    					<a href="http://www.atguigu.com">推荐</a>
    				</div>
    				<h4>欢迎前来观影</h4>
    			</template>
    		</Category>
    	</div>
    </template>
    
    <script>
    	import Category from './components/Category'
    	export default {
    		name:'App',
    		components:{Category},
    		data() {
    			return {
    				games:['植物大战僵尸','红色警戒','空洞骑士','王国']
    			}
    		},
    	}
    </script>
    
    <style>
    	.container,.foot{
    		display: flex;
    		justify-content: space-around;
    	}
    	h4{
    		text-align: center;
    	}
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    Category.vue

    <template>
    	<div class="category">
    		<h3>{{title}}分类</h3>
    		<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
    		<slot name="center">我是一些默认值,当使用者没有传递具体结构时,我会出现1</slot>
            <slot name="footer">我是一些默认值,当使用者没有传递具体结构时,我会出现2</slot>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'Category',
    		props:['title']
    	}
    </script>
    
    <style scoped>
    	.category{
    		background-color: skyblue;
    		width: 200px;
    		height: 300px;
    	}
    	h3{
    		text-align: center;
    		background-color: orange;
    	}
    	video{
    		width: 100%;
    	}
    	img{
    		width: 100%;
    	}
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    作用域插槽

    App.vue

    <template>
    	<div class="container">
    		<Category title="游戏" >
    			<template scope="jojo">
    				<ul>
    					<li v-for="(g,index) in jojo.games" :key="index">{{g}}</li>
    				</ul>
    			</template>
    		</Category>
    
    		<Category title="游戏" >
    			<template scope="jojo">
    				<ol>
    					<li v-for="(g,index) in jojo.games" :key="index">{{g}}</li>
    				</ol>
    			</template>
    		</Category>
    
    		<Category title="游戏" >
    			<template scope="jojo">
    				<h4 v-for="(g,index) in jojo.games" :key="index">{{g}}</h4>
    			</template>
    		</Category>
    	</div>
    </template>
    
    <script>
    	import Category from './components/Category'
    	export default {
    		name:'App',
    		components:{Category}
    	}
    </script>
    
    <style>
    	.container,.foot{
    		display: flex;
    		justify-content: space-around;
    	}
    	h4{
    		text-align: center;
    	}
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    Category.vue

    <template>
    	<div class="category">
    		<h3>{{title}}分类</h3>
    		<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
    		<slot :games="games">我是一些默认值,当使用者没有传递具体结构时,我会出现1</slot>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'Category',
    		props:['title'],
            data() {
    			return {
    				games:['植物大战僵尸','红色警戒','空洞骑士','王国']
    			}
    		},
    	}
    </script>
    
    <style scoped>
    	.category{
    		background-color: skyblue;
    		width: 200px;
    		height: 300px;
    	}
    	h3{
    		text-align: center;
    		background-color: orange;
    	}
    	video{
    		width: 100%;
    	}
    	img{
    		width: 100%;
    	}
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    插槽:

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

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

    使用方式:

    默认插槽:

    父组件中:
            <Category>
               	<div>html结构1</div>
            </Category>
    子组件中:
            <template>
                <div>
                   	<slot>插槽默认内容...</slot>
                </div>
            </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    具名插槽:

    父组件中:
            <Category>
                <template slot="center">
                 	 <div>html结构1</div>
                </template>
    
                <template v-slot:footer>
                   	<div>html结构2</div>
                </template>
            </Category>
    子组件中:
            <template>
                <div>
                   	<slot name="center">插槽默认内容...</slot>
                    <slot name="footer">插槽默认内容...</slot>
                </div>
            </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    作用域插槽:

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

    父组件中:
    		<Category>
    			<template scope="scopeData">
    				<!-- 生成的是ul列表 -->
    				<ul>
    					<li v-for="g in scopeData.games" :key="g">{{g}}</li>
    				</ul>
    			</template>
    		</Category>
    
    		<Category>
    			<template slot-scope="scopeData">
    				<!-- 生成的是h4标题 -->
    				<h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
    			</template>
    		</Category>
    ——
    子组件中:
            <template>
                <div>
                    <slot :games="games"></slot>
                </div>
            </template>
    		
            <script>
                export default {
                    name:'Category',
                    props:['title'],
                    //数据在子组件自身
                    data() {
                        return {
                            games:['红色警戒','穿越火线','劲舞团','超级玛丽']
                        }
                    },
                }
            </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
  • 相关阅读:
    KNN聚类算法
    面试突击24:为什么wait和notify必须放在synchronized中?
    简单两步,使用 cache 加快极狐GitLab CI/CD 构建速度
    最长连续序列(LeetCode128)
    perl语言入门学习
    深入了解Java8新特性-日期时间API之ZonedDateTime类
    Visual Studio 删除行尾空格
    谈谈SSO单点登录的设计实现
    Atlassian发布最新补贴政策,Jira/Confluence迁移上云最低可至零成本
    傅里叶在图像中的应用FFT算法---fft实战应用案例
  • 原文地址:https://blog.csdn.net/qq_46574748/article/details/132768723