vue 2.0 的使用

day01

1. Vue简介

一套用于构建用户界面的 渐进式框架
在这里插入图片描述

2. 初识Vue

2.1 搭建Vue开发环境

  • 第一步:去<a href="https://v2.cn.vuejs.org/">Vue2官网</a>,下载依赖包。

  • 第二步:在 html文件中引入 vue.js

    <!-- 引入Vue -->
    <script type="text/javascript" src="../../js/vue.js"></script>
    

    输出一下 Vue构造函数:console.log(Vue),看是否配置成功。

  • 第三步:编写脚本关闭生产提示。

    //阻止 vue 在启动时生成生产提示
    Vue.config.productionTip = false
    

    注意:如果上述方法无法关闭,可直接操作 vue.js修改 productionTip的值为 false

  • 第四步:安装开发者工具,打开浏览器的【插件管理】,直接拖动 .crx文件到浏览器即可。

  • 第五步:配置页签图标,直接复制 favicon.ico到根目录即可。


2.2 一个Hello效果

  • 实现效果:

在这里插入图片描述

  • 核心代码:

    <!-- 准备好一个容器 -->
    <div id="demo">
       <h1>Hello,{{school}}</h1>
    </div>
    
    <script type="text/javascript" >
      // 创建Vue实例,并传入配置对象
      new Vue({
         el:'#demo', //用于指定当前Vue实例服务于哪个容器,值为CSS选择器字符串
         data:{ // data用于配置数据,数据可以直接在模板中使用,值暂时写成一个对象
           school:'尚硅谷'
         }
      })
    </script>
    
  • 总结:

    1. 想让 Vue工作,就要创建一个Vue实例,且要传入一个配置对象。
    2. demo容器中的代码被称为模板,它依然符合 HTML规范,只是混入了一些特殊的 Vue语法。
    3. el 配置:用于指定当前 Vue实例服务于哪个容器,值为:css选择器字符串。
    4. data 配置:用于配置数据,数据可以直接在模板中使用,值暂时写成一个对象(以后还会写成函数)。

2.3 分析Hello效果

  1. Vue实例和容器是一一对应的,真实开发中一般只有一个 Vue实例,而且还会配合组件一起使用。

  2. data中的数据只要发生改变,模板中用到该数据的地方就会自动更新。

  3. {{xxx}}中的 xxx 要写 js 表达式,且 xxx 可以自动读取到 data中的属性。

  4. 复习一个点:【js表达式】与【 js语句】

    1. 表达式:会产生一个值,可以放在任何一个需要值的地方,例如:

      (1). 1
      (2). a
      (3). x > = 18 ? '成年' : '未成年'
      (4). 200 - 2
      (5). arr.map()

      等等…

    2. 语句(代码): 不会产生值,只是控制代码走向,例如:

      (1). if ( ) {}
      (2). for ( ) {}
      (3). try {} catch (err) {}
      等等…

  5. 相关代码:

   <!-- 准备好一个容器 -->
   <div id="demo">
     <h1>Hello,{{school}}</h1>
     <h1>Hello,{{address}}</h1>
     <h1>Hello,{{school.toUpperCase()}}</h1>
     <h1>Hello,{{school.toUpperCase().slice(0,2)}}</h1>
     <h1>Hello,{{floor}}</h1>
     <h1>Hello,{{floor > 6 ? '高楼层' : '低楼层'}}</h1>
     <h1>Hello,{{1+1}}</h1>
     <h1>Hello,1+1</h1>
     <h1>Hello,{{floor+1}}</h1>
   </div>
   
   <!-- 创建Vue实例 -->
   <script type="text/javascript" >
     new Vue({
         el:'#demo',
         data:{
           school:'atguigu',
           address:'宏福科技园',
           floor:19
         }
       })

</script>

3. 了解开发者工具

  1. 视角一

在这里插入图片描述
2. 视角二
在这里插入图片描述

4. Vue的模板语法

4.1 插值与指令

  1. 插值语法(简单):

    功能:用于操作标签体,可以在标签体的指定位置插入数据。
    写法:{{xxx}}xxxjs 表达式,且可以自动读取到 data中配置的所有属性。

  2. 指令语法(复杂):

    功能:用于操作标签(标签属性、标签体、绑定事件…)
    举例:v-bind:href = "xxx",xxx 是 js 表达式,且可以自动读取到 data中配置的所有属性。

  3. 备注:Vue中有很多的指令,形式都是 v-???,此处我们只是拿 v-bind举个例子。

  4. 务必搞懂如下代码:

   <a 
     v-bind:href="url"
     a="url" 
     v-bind:b="url" 
     c="1+1" 
     v-bind:d="1+1"
     e="url.toUpperCase()"
     v-bind:f="url.toUpperCase()"
   >
     点我去{{school}}学习
   </a>

   <script>
     new Vue({
       el:'#demo',
       data:{
         school:'尚硅谷',
         url:'http://www.atguigu.com'
       }
     })
   </script>

4.2 v-bind 的简写

  • v-bind: 可以简写为 :
  • 只有 v-bind指令才能简写为 : 别的指令不行。
  • 其他的指令有其他的简写形式、但并不是所有的指令都有简写形式。

5. 数据绑定

  • Vue中有两种绑定数据的方式:

    1. 单向数据绑定(v-bind):数据只能从 data流向页面。
    2. 双向数据绑定(v-model):数据不仅能从 data流向页面,也能从页面流回 data
  • 注意点:

    1. v-model目前只能用在输入类(表单类)元素上(以后还能用写在组件标签上)。
    2. v-model默认收集的是 value值,所以 v-model:value="xxx" 可以简写为 v-model="xxx"
  • 核心代码:

    <!-- 准备好一个容器-->
    <div id="demo">
      <h1>欢迎来到{{school}}</h1>
      <!-- 单向绑定:<input type="text" v-bind:value="address"> <br> -->
      <!-- 双向绑定:<input type="text" v-model:value="address"> -->
      <br>
      <!-- 上面的13、14行的简写形式如下 -->
      单向绑定:<input type="text" :value="address"> <br>
      双向绑定:<input type="text" v-model="address">
    
      <!-- 下面这行代码是有问题的,会报错,因为v-model只能用在输入类(表单类)元素上 -->
      <!-- <a v-model:href="url">点我去{{school}}学习2</a> -->
    </div>
    
    <script type="text/javascript" >
      new Vue({
        el:'#demo',
        data:{
          school:'尚硅谷',
          url:'http://www.atguigu.com',
          address:'宏福科技园'
        }
      })
    </script>
    

6. el 与 data 的写法

6.1 el 的三种写法

  • 第一种写法:值为 css选择器字符串

    new Vue({
      el:'#demo'
      //******
    })
    
  • 第二种写法:值为一个真实 DOM元素 —— 几乎不用,了解即可。

    new Vue({
      el:document.getElementById('demo'),
      //******
    })
    
  • 第三种写法:使用 $mount方法去替代 el配置。

    new Vue(/******/).$mount('#demo')
    
    

6.2 data 的两种写法

  • 第一种(对象式)

    data:{
      school:'尚硅谷'
    }
    
    
  • 第二种(函数式)—— 最近不用,以后会用。

    data(){
      return {
        school:'尚硅谷'
      }
    }
    
    

7. 理解MVVM

  1. M:模型(Model) :data中的数据。
  2. V:视图(View) :模板。
  3. VM:视图模型(ViewModel) : Vue实例对象。

在这里插入图片描述

8. 认识一下vm

  1. vm身上有很多 $开头的属性或方法,这是给我们程序员用的(但也不是都用)。

  2. data中所配置的属性,也不知道怎么了(后面会详细说),最终都出现在了 vm身上。

  3. vm身上所有的属性,以及顺着 vm能找到的东西,都能在模板中直接使用,但往往我们使用的只是那些:配置项中所写的东西。

  4. 务必搞懂如下代码:

    <!-- 准备好一个容器-->
    <div id="demo">
      <h1>{{school}}欢迎你!</h1>
      <h2>测试1:{{a}}</h2>
      <h2>测试2:{{b}}</h2>
      <h2>测试3:{{_c}}</h2>
      <h2>测试4:{{$attrs}}</h2>
      <h2>测试5:{{toString}}</h2>
      <h2>测试6:{{d}}</h2>
    </div>
    
    <script type="text/javascript">
      Object.prototype.d = 9
      let vm = new Vue({
        el: '#demo',
        data: {
          school: '尚硅谷',
          a: 1,
          b: 2
        }
      })
      // 输出Vue实例对象 —— vm
      console.log(vm)
    </script>
    
    

day02

1. 复习Object.defineProperty

  1. Object.defineProperty,能给对象追加属性,并且可以对属性进行“高级定制”。

    //定义一个对象
    let person = {name:'张三',sex:'女'}
    
    //通过Object.defineProperty,也可以给person对象追加一个age属性,且可以对age进行“高级定制”。
    Object.defineProperty(person,'age',{
      value:90,//值
      enumerable:true, //控制属性是否可以枚举(是否参与遍历),默认值false
      configurable:true, //控制属性是否可以删除,默认值false
      writable:true,//控制属性是否可以被修改,默认值false
    })
    
    
  2. Object.definePropertygetset配置:

    //定义一个number变量
    let number = 18
    
    // 定义一个person对象
    let person = {name:'张三',sex:'女'}
    
    //借助Object.defineProperty去追加age属性
    Object.defineProperty(person,'age',{
      enumerable:true,
      //get函数(getter)何时执行?—— 有人读取person对象的age属性时执行
      //get函数(getter)中的this是谁? —— 当前对象(person)
      get:function peiqi(){
        console.log('getter执行了',this)
        return number
      },
      //set函数(setter)何时会被调用? —— 有人修改person对象的age属性时执行
      //get函数(setter)中的this是谁? —— 当前对象(person)
      set:function qiaozhi(value){
        console.log('有人修改了person的age属性,值为:',value,this)
        number = value
      }
    })
    
    

2. 数据代理

2.1 何为数据代理

通过一个对象代理对另一个对象中属性的操作(读/写)。

2.2 Vue中的数据代理

  • 前情提要:我们 new Vue(options)时传入的那个 dataVue收到后放在了 vm上,名为 _data

  • Vue中的数据代理:通过 vm来对 _data中属性的操作(读/写)。

  • Vue中数据代理的好处:模板中可以更加方便的操作 _data中的数据,例如:

    若无数据代理,这么写:{{_data.name}} —— 很麻烦。

    若有数据代理,这么写:{{name}} —— 香!

    注意:此时我们先不关注 _data中为什么也有 gettersetter,过几天就会说。


2.3 数据代理的原理

  1. 遍历 _data对象中所有的属性,通过 Object.defineProperty()一个一个都添加到 vm上。

  2. 随后 vm上就拥有了 _data中所有的属性,且都有自己的 gettersetter

  3. gettersetter内部操作(读/写)的是 _data中对应的属性。

在这里插入图片描述

3. 事件处理

3.1 事件绑定

  1. 使用 v-on:xxx@xxx 绑定事件,xxx是事件名,同原生 DOM事件名。

    <button v-on:click="showTel">点我查看学校电话1</button>
    <button @click="showTel">点我查看学校电话2</button>
    
  2. 事件的回调函数,要配置在 methods中(data中写数据、methods中写方法)。

  3. Vue在触发事件回调时,会传入一个默认的参数 ——事件对象(event) 。

  4. methdos中的函数最终也会出现在 vm上(但不存在数据代理)。

    const vm = new Vue({
      el:'#demo',
      data:{
        school:'尚硅谷',
        tel:'10086',
      },
      methods:{
        showTel:(event)=>{
          console.log(this)
          alert(this.tel)
        }
      }
    })
    console.log(vm)
    

通常情况下,由 Vue管理的函数(目前只学了:data函数、methods中的函数),请务必写成普通函数,这样才能保证:thisvm,一旦写成了箭头函数,this就不再是 vm了。

3.2 事件传参

  1. 不传递参数:@click="test1"test1方法会收到一个 event(事件对象)。
  2. 传一个参数:@click="test2(6)"test2方法只会收到一个 6
  3. 传多个参数:@click="test3(6,7,8)"test3方法会收到:6、7、8
  4. 传参+事件对象:@click="test4(6,$event)"test4方法会收到:事件对象6
  5. 传递的参数也可以是 data中的数据,例如 @click="test5(school)"

以下写法有点傻:

<button @click="test($event)">按钮</button>
<button @click="test()">按钮</button>

3.3 事件修饰符

  1. prevent:可以阻止默认行为。

  2. stop:可以阻止冒泡。

  3. once:事件只触发一次。原理是当调用一次之后,vue底层会删除这个事件

  4. 事件修饰符可以串联:

    <div @click="test" class="wraper">
        <a href="xxx" @click.prevent.stop="test">按钮</a>
    </div>
    
    

3.4 键盘事件

  • Vue中的按键别名:

    1. 回车 => enter
    2. 删除 => delete (退格 、 删除 按键)
    3. 退出 => esc
    4. 空格 => space
    5. 换行 => tab (必须配合 keydown去使用)
    6. 上 => up
    7. 下 => down
    8. 左 => left
    9. 右 => right
  • 也可以使用 event.keyCode去指定具体的按键,例如:@keyup.13` 绑定回车。

  • 有四个系统修饰键,用法比较特殊(了解即可),分别是:ctrlaltshiftmeta,规则如下:

    1. 若配合 keydown使用:正常触发事件。
    2. 若配合 keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
	<input @keyup.enter="show" type="text" placeholder="按下回车提示用户输入的内容"><br>
    <input @keyup.delete="show" type="text" placeholder="按下删除提示用户输入的内容"><br>
    <input @keyup.esc="show" type="text" placeholder="按下退出提示用户输入的内容"><br>
    <input @keyup.space="show" type="text" placeholder="按下空格提示用户输入的内容"><br>
    <input @keydown.tab="show" type="text" placeholder="按下换行提示用户输入的内容"><br>
    <input @keyup.up="show" type="text" placeholder="按下↑提示用户输入的内容"><br>
    <input @keyup.down="show" type="text" placeholder="按下↓提示用户输入的内容"><br>
    <input @keyup.left="show" type="text" placeholder="按下←提示用户输入的内容"><br>
    <input @keyup.right="show" type="text" placeholder="按下→提示用户输入的内容"><br>
    <br>
    <input @keydown.ctrl="show" type="text" placeholder="按下ctrl"><br>
    <input @keydown.alt="show" type="text" placeholder="按下alt"><br>
    <input @keydown.shift="show" type="text" placeholder="按下shift"><br>
    <input @keydown.meta="show" type="text" placeholder="按下meta"><br>
    <br>
    <input @keyup.ctrl="show" type="text" placeholder="按下ctrl"><br>
    <input @keyup.alt="show" type="text" placeholder="按下alt"><br>
    <input @keyup.shift="show" type="text" placeholder="按下shift"><br>
    <input @keyup.meta="show" type="text" placeholder="按下meta"><br>

4. 姓名案例

4.1 插值语法实现

  1. 总结:用插值语法实现姓名案例,不是很好,因为模板过于复杂。

  2. 核心代码:

    <span>{{firstName.slice(0,1).toUpperCase() + firstName.slice(1)}}-{{lastName}}</span>
    

4.2 methods实现

  1. 总结:使用 methods去实现姓名案例,比使用插值好了一些,但存在一些问题:

    • 没有缓存,多次使用同样的值,函数会执行多次,效率不高。
    • 无关数据若发生变化,也会导致方法执行。
  2. 核心代码:

    methods:{
        getFullName(){
            console.log('getFullName')
            return this.firstName.slice(0,1).toUpperCase() + this.firstName.slice(1) + '-' + this.lastName
        },
    }
    
    

5. 计算属性

学习计算属性前,请先把【姓名案例】分别用:插值语法methods,去实现一下。

  1. 定义:要用的数据(属性)不存在,要根据已有数据(属性)计算得来。
  2. 原理:底层是通过 Objcet.defineProperty实现的。
  3. 优势:与 methods实现姓名案例相比,内部有缓存机制,效率更高,且调试方便。

5.1 get函数

  • get函数何时调用?
    1. 初次读取 fullName时。
    2. 计算 fullName所【依赖的数据】发生改变时。
  • get函数中的 this谁? —— vm

注意:计算属性最终也会出现在 vm上,在模板中可直接使用,但千不要加 .get()

5.2 set函数(用的少)

  • set函数何时调用?—— 仅当计算属性被修改时。

  • set函数中的 this是谁? —— vm

  • 什么是修改计算属性?

    这是修改:this.fullName = 'li-si'

    这是读取:this.fullName

    注意:this.firstName = 'li' ,这是修改 firstName

代码示例:

computed:{
  fullName:{
    get(){
      /**********/
    }
    set(value){
      /**********/
    }
  }
}


5.3 简写方式

  1. 什么时候才能简写?—— 计算属性不会修改时(不需要 set函数时),才能用简写形式。

  2. 语法实例:

    computed:{
      fullName(){
        return xxxxx
      }
    }
    
    

6. 天气案例

如果回调函数的逻辑很简短,那么可以写在引号里:

<button @click="isHot = !isHot">切换天气</button>

day03

1. 监视属性

1.1 基本使用

监视属性又称侦听器,学习监视属性前,请先完成:天气案例。

  1. 作用:当被监视的属性变化时, 回调函数(handler)自动调用,至于回调函数中做什么,要看具体需求。

  2. 具体编码:

    watch:{
      isHot:{
        handler(newValue,oldValue){ //(新数据,旧数据)
          /*********/
        }
      }
    }
    
  3. 注意点:

    • 被监视的可以是:属性(data),也可以是计算属性(computed)。
    • 监视的属性必须存在,才能进行监视,若监视了不存在的属性,也不会报错!

1.2 立即监视

  1. 作用:让 Vue初次渲染时,数据还没有发生变化,就调用一下监视的回调函数(handler
  2. 具体配置:immediate:true

1.3 深度监视

  1. Vue底层一直可以监测对象内部值的改变(且无论对象有“深”)。
  2. Vue给我们提供的 watch配置,默认不监测对象内部属性的改变。
  3. 配置 deep:true可以监测对象内部属性的改变。
  4. 使用 watch时,要根据数据的具体结构,来决定是否采用深度监视。

1.4 特殊写法

当数据层级较深,但只想监视里面的某一个数据时候,可以不开启深度监视,只针对某个属性进行监视,例如:

new Vue({
    el:'#demo',
    data:{
        a:{
            b:{
                c:{
                    d:1
                }
            }
        }
    },
    watch:{
        'a.b.c.d':{
            handler(value){
            	console.log('a.b.c.d变化了')
        	}
        }
    }
})

1.5 简写形式

  1. 明确:当不需要【立即监视】、【深度监视】的时候,才可以用简写形式。

  2. 示例代码(isHot函数,就相当于完整写法中的 handler):

    watch:{
    	isHot(){
        	/*********/
      	}
    }
    

1.6 $watch(了解即可)

通过 vm.$watch也可以进行监视

vm.$watch('isHot',{
  handler(newValue,oldValue){ 
    /******/
  }
})

2.梳理配置项

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>梳理配置项</title>
    <!-- 引入Vue -->
    <script type="text/javascript" src="../../js/vue.js"></script>
  </head>
  <body>
    <!-- 准备好一个容器-->
    <div id="demo">
      <!-- a怎么用 -->
      <!-- <h1 :x="a">{{a}}</h1> -->
      <!-- <input type="text" v-model="a"> -->
      <!-- <button @click="a+=1">点我</button> -->
    
      <!-- b怎么用 -->
      <!-- 19行、20行,没有语法上的错误,但使用的没意义 -->
      <!-- <h1 :x="b">{{b}}</h1> -->
      <!-- <input type="text" v-model="b"> -->
      <!-- <button @click="b">点我</button> -->
      <!-- <h1>{{b()}}</h1> -->

      <!-- c能怎么用 -->
      <!-- <h1 :x="c">{{c}}</h1> -->
      <!-- 下面这行能写,但要记得,配一个setter -->
      <!-- <input type="text" v-model="c"> -->
      <h1>{{c}}</h1>

    </div>

    <script type="text/javascript">
      const vm = new Vue({
        el:'#demo',
        data:{
          a:1,
        },
        methods:{
          b(){
            console.log('b执行了')
            return 99
          }
        },
        computed:{
          c(){
            return (this.a+1)*10
          }
        },
        watch:{}
      })
      console.log(vm)
    </script>
  </body>
</html>

3. computed与watch

computedwatch之间的区别与联系:

  • computed能完成的功能,watch都可以完成,且通常 computed的写法会更简便。

    例如:姓名案例,computedwatch都能完成,但 computed写起来,更简单。

  • watch能完成的功能,computed不一定能完成。

    例如:还做姓名案例,但要求:名改完 1秒钟后,全名再变。

3.1 computed

  • 侧重在【算】,核心是:计算出来的值。
  • return来输出计算的结果。
  • 不能异步计算。

3.2 watch

  • 侧重在【监视】,核心是:xxx变了,我要做 ???事。
  • 无需 return,靠内部逻辑去完成要做的事。
  • 能开启异步任务。

4. Vue中使用函数的原则

  • Vue所管理的函数,务必写成普通函数,例如:datamethods中的函数、computed中的函数、watch中的函数。
  • 不是 Vue所管理的函数,最好写成箭头函数,例如:数组方法的回调函数、ajax请求的回调函数、定时器的回调函数、Promise的回调函数等等。

遵循上述两个原则的目的只有一个:让 this的指向是 vm

5. 条件渲染

5.1 v-show

  1. 语法:v-show="表达式"
  2. 适用于:切换频率较高的场景。
  3. 特点:不展示的 DOM元素但是依然存在在,仅仅是使用样式display:none隐藏掉了,不破坏 DOM结构。

5.2 v-if

  1. 语法:

    v-if="表达式" 
    v-else-if="表达式"
    v-else
    
  2. 适用于:切换频率较低的场景。

  3. 特点:不展示的 DOM元素直接被移除。

    注意点:

    1. v-if可以和:v-else-ifv-else一起使用,但要求结构不能被“打断”。
    2. 如果使 用 v-if,可能会出现无法获取元素的问题。
  4. 实际开发中,以下这个场景我们会使用v-if

    <!-- 准备好一个容器-->
    <div id="demo">
      <h1 v-if="person.age">真实年龄:{{person.age.realAge}}</h1>
      <button @click="getNetWorkData">获取网络数据</button>
    </div>
    
    <script type="text/javascript">
      new Vue({
        el:'#demo',
        data:{
          person:{}
        },
        methods: {
          getNetWorkData(){
            this.person = {
              age:{
                foreignAge:29,
                realAge:45
              }
            }
          }
        },
      })
    </script>
    

6. 列表渲染

6.1 v-for 指令

  1. 指令:v-for
  2. 作用:用于遍历数据,生成多个结构。
  3. 语法:v-for="(item,index) in xxx" :key="????"

通俗理解:想生成多个谁,就在谁身上加 v-for,别忘了写 key

key的使用原则(同 react):有唯一值就用唯一值(身份证号、手机号、学号…),没有就用索引值。

6.2 详聊 v-for

  1. 遍历数组

    <ul>
      <li v-for="(item,index) in arr" :key="index"> {{item}} </li>
    </ul>
    
  2. 遍历对象

    <li v-for="(value,key,index) in car" :key="index"> 
      {{value}} - {{key}} - {{index}}
    </li>
    
  3. 遍历字符串

    <li v-for="(char,index) in str" :key="index"> 
      {{char}} - {{index}} 
    </li>
    
  4. 遍历指定次数

    <li v-for="(number,index) in 10" :key="index"> 
      {{number}} - {{index}}
    </li>
    
  5. v-for很健壮,遍历如下内容都不会报错,并且不会渲染任何内容

    <h1 v-for="(a,b) in null">尚硅谷</h1>
    <h1 v-for="(a,b) in undefined">尚硅谷</h1>
    <h1 v-for="(a,b) in '' ">尚硅谷</h1>
    <h1 v-for="(a,b) in true ">尚硅谷</h1>
     <h1 v-for="(a,b) in false">尚硅谷</h1>
    <h1 v-for="(a,b) in [] ">尚硅谷</h1>
    

<h1 v-for="(a,b) in NaN">尚硅谷</h1> 不能循环NaN 会报错 错误的写法

6.3 人员案例

  1. 可以使用 watchcomputed分别去实现一下,发现用 computed更简单。
  2. 用到了:字符串的 includes方法,数组的 filter方法。

6.4 v-for和v-if 不建议连用 (vue2.0版本)

** v-for的优先级比v-if的优先级高。先for出来再v-if删除dom,会干无用功**

day04

1. 其它指令

  1. 我们学过的指令:

    • v-bind : 单向数据绑定, 可简写为 :xxx
    • v-model : 双向数据绑定
    • v-for : 遍历数组 / 对象 / 字符串 / 指定次数
    • v-on : 绑定事件监听, 可简写为 @
    • v-if : 条件渲染(动态控制节点是否存在)
    • v-else-if : 条件渲染(动态控制节点是否存在)
    • v-else : 条件渲染(动态控制节点是否存在)
    • v-show : 条件渲染 (动态控制节点是否展示)

v-text

作用:向其所在的节点中渲染文本内容。

与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。

<h1 v-text="str">张三</h1>

v-html

作用:向指定节点中渲染包含 html结构的文本。
与插值语法的区别:

  1. v-html会替换掉节点中所有的内容,{{xx}}则不会。
  2. v-html可以识别 html结构。
  3. 备注:v-html存在一些安全性问题,因为结构中很有可能包含恶意脚本。
	<h1 v-html="str"></h1>

	new Vue({
	  el:'#demo',
	  data:{
	     str:'<a href="javascript:alert(250)">兄弟好东西,快来</a>'
	  }
	})

v-once

  1. v-once所在节点在初次动态渲染后,就视为静态内容了。
  2. 以后数据的改变不会引起 v-once所在结构的更新,可以用于优化性能。
 <div id="demo">
   <h2 v-once>初始的n值是:{{n}}</h2>
    <h2>当前的n值是:{{n}}</h2>
    <button @click="n+=1">点我n+1</button>
  </div>

  <script type="text/javascript">
    new Vue({
      el:'#demo',
      data:{
        n:1
      }
    })
  </script>

v-pre

跳过这个元素和它的子元素的编译过程,一般用在大量不使用 Vue语法的结构中。

<div v-pre>
 <h1>你好同学,欢迎来到尚硅谷</h1>
  <h2>想一夜暴富吗?</h2>
  <h3>想一步登天吗?</h3>
  <h4>想赢取白富美吗?</h4>
  <p>
    那要怎么做?—— 学前端!!
  </p>
  <strong>要好好学!</strong>
</div>

v-cloak

  1. 本质是一个特殊属性,Vue接管容器后,会删掉 v-cloak属性。
  2. 使用 css配合 v-cloak可以解决网速慢时,页面展示出 {{xxx}}的问题。
<style>
    [v-cloak] {
       display: none;
     }
   </style>
<body>
    <div id="demo">
      <h1 v-cloak>欢迎来到{{school}}</h1>
    </div>
    
    <script type="text/javascript" src="../../js/vue.js"></script>

    <script type="text/javascript" >
      new Vue({
        el:'#demo',
        data:{
          school:'尚硅谷'
        }
      })
    </script>
  </body>

2. 数据劫持

2.1 何为数据劫持

  • 概念:捕获对象属性变化的一种手段。

    前端的响应式框架通常都会对数据进行劫持,这样当数据发生变化时,才能自动更新相关的视图,或执行其他逻辑。

2.2 Vue中的数据劫持

  1. 具体实现方式:

    • Vue会将所有层级的属性,全都改为 gettersetter的形式,随后放在 _data中。
    • _data中的数据放生变化时,对应的 setter会执行,在 setter中:①修改数据、②更新界面。
  2. 图示:

2.3 总结_数据代理 _数据劫持

  • 数据代理(简单,vm身上的那点事):

    1. 目的:让程序员更加方便的读取、修改到 _data中属性。
    2. 原理:Object.defineProperty
    3. 体现:vm身上有 _data里的所有属性,且有每一个属性,都有自己的 proxyGetterproxySetter
    • 当修改 vm上的属性时,该属性对应的 proxySetter就会调用,去修改 _data中对应的属性。
    • 当读取 vm上的属性时,该属性对应的 proxyGetter就会调用,去读取 _data中对应的属性。
  • 数据劫持(_data里的那点事):

    1. 目的:为了实现响应式(什么是响应式?—— 数据变页面自动更新),有了数据劫持,就可以捕获到数据的改变,进而重新解析模板,更新界面。
    2. 原理:Object.defineProperty
    3. 体现:_data身上的每一个属性不直接给值,都变为:reactiveSetterreactiveGetter形式。
    • 当修改 _data上的属性时,该属性对应的 reactiveSetter就会调用。且在 reactiveSetter中Vue会:维护数据、更新页面。
    • 当读取 _data上的属性时,该属性对应的 reactiveGetter就会调用,返回对应的值。

3. Vue中操作数组

  1. Vue中,修改数组中的某一项,请务必要用如下7个方法:

    push()pop()shift()unshift()splice()sort()reverse()

  2. Vue在底层包裹了数组的7个变更方法,本质就是做了两件事:

    ​ ① 调用原生对应的方法对数组进行更新。

    ​ ② 更新页面。

4. 收集表单数据

  1. 若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。
  2. 若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
  3. 若:<input type="checkbox"/>
    • 没配置inputvalue属性,那么收集的就是checked(勾选 或 未勾选,是布尔值)
    • 配置了inputvalue属性:
      • v-model的初始值是非数组,那么收集的就是checked(勾选 或 未勾选,是布尔值)。
      • v-model的初始值是数组,那么收集的就是value组成的数组。
<body>
    <!-- 准备好一个容器-->
    <div id="demo">
      <form>
        账号:<input type="text" v-model="account"> <br><br>
        密码:<input type="password" v-model="password"> <br><br>
        性别:
          男<input type="radio" name="sex" value="male" v-model="gender"><input type="radio" name="sex" value="female" v-model="gender">
        <br><br>
        爱好:
          抽烟<input type="checkbox" value="smoke" v-model="hobby">
          喝酒<input type="checkbox" value="drink" v-model="hobby">
          学习<input type="checkbox" value="study" v-model="hobby">
        <br><br>
        所属校区:
          <select v-model="city">
            <option value="">请选择城市</option>
            <option value="beijing">北京</option>
            <option value="shenzhen">深圳</option>
            <option value="shanghai">上海</option>
            <option value="wuhan">武汉</option>
            <option value="xian">西安</option>
            <option value="chengdu">成都</option>
          </select>
        <br><br> 
        其他信息:
          <textarea v-model="other"></textarea><br><br>
          <input type="checkbox" v-model="agree">阅读并接受<a href="#">用户协议</a>
        <br><br>
        <button>提交</button>
      </form>
    </div>

    <script type="text/javascript">
      new Vue({
        el:'#demo',
        data:{
          account:'',
          password:'',
          gender:'female',
          hobby:[],
          city:'',
          other:'',
          agree:false
        }
      })
    </script>
  </body>

5. 生命周期

5.1 何为生命周期

  1. 生命周期,又称:生命周期函数、生命周期钩子。
  2. 是什么? —— Vue在关键时刻帮我们调用的一些特殊名称的函数。

5.2 生命周期图

beforeCreate() 数据代理、数据劫持创建之前
created() 数据代理、数据劫持创建完毕
beforeMount() 挂载(真实DOM放入页面)之前
mounted() 挂载(真实DOM放入页面)完毕
beforeUpdate() 更新之前
updated() 更新完毕
beforeDestroy() 销毁之前
destroyed() 销毁完毕

  1. 生命周期函数的名字不可更改,但其中的具体内容,看具体需求。
  2. 生命周期函数中的this指向是vm或 组件实例对象。

5.3 总结

  1. 哪个钩子中不能访问data中的数据、methods中的方法? —— beforeCreate
  2. 想给vm上追加一些属性,最早可以在哪个钩子中操作? —— beforeCreate
  3. data中的数据、methods中的方法,最早可以在哪个钩子中获取? —— created
  4. 哪个钩子中数据和页面其实是不同步的?—— beforeUpdate
  5. 常用的钩子有哪些?
    • mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】
    • beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。

day05

1. 组件化

1.1 对组件的理解

概念:应用中局部功能代码资源的集合。

1.2 准备一个效果

展示:学校、人员 相关信息。

1.3 基本使用

Vue中使用组件的三大步骤

  • 第一步:创建组件

    1. 如何创建组件?—— 使用Vue.extend(options)方法。
    2. 其中的optionsnew Vue(options)几乎一样,但也有点小区别,区别如下:
      • 组件配置中不能写el,为什么?—— 由vm去决定服务哪个容器,组件跟着走就ok了。
      • 组件配置中data必须写成函数,为什么? —— 避免组件复用时产生数据的干扰。
 const Person = Vue.extend({
   nane:'Person',
   template:`
      <div>
        <h2>人员信息</h2>
        <h4>姓名:{{personName}}</h4>
        <h4>年龄:{{personAge}}</h4>
        <button @click="showPersonInfo">点我提示个人信息</button>
      </div>
    `,
    data(){
      return {
        personName:'瑶瑶',
        personAge:18,
      }
    },
    methods:{
      showPersonInfo(){
        alert(`我叫${this.personName},我今年${this.personAge}岁了`)
      }
    }
  })
  • 第二步:注册组件

    new Vue({...})时,使用components配置。

  new Vue({
   el:'#demo',
     // 第三步:编写组件标签
     template:`
       <div>
         <Person></Person>
   	   </div>
     `,
     // 第二步:注册组件
     //components:{Person:Person}
      components:{Person}//简写
   })
  • 第三步:使用组件(编写组件标签)。

    <Person> </Person>

1.4 组件名_组件标签

关于组件名:

  1. 一个单词组成:
    • 第一种写法:(首字母小写):school
    • 第二种写法:(首字母大写):School —— 推荐
  2. 多个单词组成:
    • 第一种写法:kebab-case命名,例如:atguigu-school
    • 第二种写法:CamelCase命名,例如:AtguiguSchool

可以使用name配置项,指定组件在开发者工具中的名字。

关于组件标签

  • 第一种写法:<组件名></组件名>

  • 第二种写法:<组件名/>

1.5 App组件的使用

通常使用App组件,作为所有组件的根组件。

// 创建一个App组件
let App = Vue.extend({
	components:{Person,School},
	template:`
		<div>
            <Person></Person>
            <hr>
            <School></School>
        </div>`
})

1.6 注册全局组件

  1. 若某个组件,需要在很多的地方使用,可以进行全局注册
  2. 语法:Vue.component('组件名',具体的组件)
Vue.component('Welcome',Welcome)

1.7 VueComponent

  1. 组件的本质是一个构造函数,名为:VueComponent

  2. VueComponent,不是我们定义的,也不是引入了vue.js就有的,而是Vue.extend()生成的。

  3. 我们只需要写 <Person></Person><Person/>Vue底层就会帮我们执行: new VueComponent()

    简记:定义组件是在创建VueComponent,编写组件标签是在new VueComponent()

  4. 关于this的指向:

    1. new Vue(options)中,this指向是vm
    2. Vue.extend(options)中:this指向是vc

    简记:

    • 创建vm时,各种配置函数中的this就是vm
    • 创建组件时,各种配置函数中的this就是vc
  5. 备注:vc是一个小型的vm,但与vm也有点小不同,例如:vm可配置el,而vc不能配置。

1.8 Vue.extend 的简写

  • 完整写法:

    //定义一个Person组件
    let Person = Vue.extend({
        name:'Person',
        template:`此处写结构`
    })
    
  • 简写方式:

    所谓简写方式,其实就是不写Vue.extend(),直接写配置对象。

    //定义一个Person组件
    let Person = {
        name:'Person',
        template:`此处写结构`
    }
    

2. 单文件组件

  • 文件的后缀名为.vue

  • 具体格式为:

    <template>
       <!-- 此处写结构 -->	
    </template>
    
    <script>
       export default {
         name:'Hello'
       }
    </script>
    
    <style>
    	/*此处写样式*/
    </style>
    
  • 安装插件:


    在这里插入图片描述

3.准备工作(无代码)

● 创建 Vue 脚手架

  • 第一步:npm i @vue/cli -g(只是第一次执行,以后就不用了)。

  • 第二步:在你喜欢的位置,打开命令行工具(CMD),执行命令:vue create hello

    1. hello是项目名称,可以随意修改,但最好别写:中文、特殊字符等。

    2. 若出现如下提示,按y即可。

      <img src="http://49.232.112.44/images/setp1.png" alt="image-20220720225357592" style="zoom:100%;"
      />

    3. 请选择:Default ([Vue 2] babel,eslint)

    4. 选择:Use NPM

  • 第三步:使用Vscode打开hello文件夹,执行命令:npm run serve,出现如下画面,代表成功。

● 脚手架结构说明

├── node_modules 项目依赖包
├── public
│ ├── favicon.ico: 页签图标
│ └── index.html: 主页面

├── src
│ ├── assets: 存放公共静态资源(公用的:图片、字体等等)
│ │ └── logo.png
│ │
│ │── components: 存放组件
│ │ └── HelloWorld.vue
│ │
│ │── App.vue: 汇总所有组件
│ │── main.js: 入口文件

├── .gitignore : git 忽略清单
├── babel.config.js : babel 配置文件
├── jsconfig.json : VScode 配置文件
├── package-lock.json :包版本清单
├── package.json : 依赖包清单
├── README.md : 应用描述文件
├── vue.config.js : 脚手架配置文件

1. 编写一个App组件

  • 删掉public文件夹,删掉src文件夹,我们自己编写一个App组件。

  • 注意:main.js中创建vm时,不要写templatecomponents

    import Vue from 'vue'
    import App from './App'
    
    Vue.config.productionTip = false
    
    new Vue({
      el:'#app',
      // template:`<App/>`, //不要写这行
      // components:{App} //不要写这行
      
      // 上述的template和components合并成下面的render配置项。
      render:h => h(App)
      //完整写法
      /*render:(helper)=>{
      		return  helper(App)
      }*/
    })
    

2. 配置语法检查

  1. 第一种方式://eslint-disable-next-line

  2. 第二种方式:/*eslint-disable*/

  3. 第三种方式:vue.config.js中配置 ,具体配置如下:

    const { defineConfig } = require('@vue/cli-service')
    module.exports = defineConfig({
        transpileDependencies: true, 
        lintOnSave:false // ======> 追加这句话,用于关闭语法检查。
    })
    

    备注:vue.config.js可以对脚手架进行个性化定制,详情见:https://cli.vuejs.org/zh

3. Person与School

  • 第一步:删掉脚手架中的publicsrc,只保留node_modules和一些配置文件。

  • 第二步:建立好如下文件(文件具体内容见代码):

    ├── public
    │   ├── favicon.ico
    │   └── index.html
    ├── src
    │   │── components
    │   │ 	└── Person.vue
    │   │ 	└── School.vue
    │   │── App.vue
    │   │── main.js
    
  • 第三步:运行看效果。

    必须把这个效果敲的特别熟!!!

4. 不同版本的Vue

  1. vue.jsvue.runtime.xxx.js的区别:

    1. vue.js是完整版的Vue,包含:核心功能 + 模板解析器
    2. vue.runtime.xxx.js是运行版(精简版)的Vue,只包含:核心功能,没有模板解析器。
  2. 因为vue.runtime.xxx.js没有模板解析器,所以new Vue时不能使用template这个配置项。

  3. vue.runtime.xxx.js需要使用render函数接收到的createElement函数去指定具体内容。

  4. 具体编码:

    //创建vm
    new Vue({
    	el:'#app',
    	render: h => h(App)
    //	render: (createElement) => createElement(App)
    })
    

5. 局部样式

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

6. ref

  1. 用来给元素或子组件打标识(id的替代者)

  2. 应用在html标签上,获取的是真实**DOM元素**。

  3. 应用在组件标签上是 组件实例对象(vc)

  4. 使用方式:

    1. 打标识:
     <h1 ref="xxx">.....</h1><School ref="xxx"></School>
  1. 获取标识对应的内容( DOM元素 或 组件实例对象):

    this.$refs.xxx
    

day06

1.props

1. props 基本使用

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

  1. 传递数据:

    <Person :name="name" :car="car" :age="age"/>
    
  2. 接收数据:

    props:['name','car','age']
    

接收到的prop最终都出现在:组件实例 —— vc上。

2. props 不可修改

props是只读的,不可修改。

  1. 对于基本类型的props:修改会报错,但页面依然会更新。
  2. 对象或数组类型的props
    • 若修改的是整个对象或数组(地址值发生变化),会报错。
    • 若修改的是对象或数组中的内容(地址值不变),不会报错 —— 但依然不推荐这样做。

注意:props收到的属性,不能和data冲突,若冲突了,以props为主,且会有警告。

3. props 的三种接收方式

注意点:

  1. 第一种方式(只接收):

    props:['name','age','car']
    
  2. 第二种方式(接收 + 限制类型):

    props:{
    	name:String,
    	age:Number,
    	car:Object
    }
    

    第三种方式(接收、限制类型、配置必要性、指定默认值):

    props:{
      name:{
        type:String,
        default:'张三',
        required:true
      },
      car:{
        type:Object,
        default(){
          return {a:1}
        }
      },
      age:{
        type:Number,
        default:90,
        required:true
      }
    },
    

4. props实现子传父

数据在哪里,修改数的方法就在哪里,或者说:只有数据的拥有者,才能修改数据。

  1. 父给子传递一个函数。
  2. 子收到函数后,在合适的时候调用函数,并传递参数,从而实现:子传父。

2. v-model 的拆分

有些时候v-model的双向绑定会让我们犯错误,所以我们需要对v-model进行拆分。

例如这种场景:v-model="xxx"中的xxx是来自于props中的值,而props的值是不可修改的,这时就需要对v-model进行拆分,核心思路是:想办法联系父亲,让父亲改。

1. 普通输入框

拆分前:

<input type="text" v-model="str">

拆分后:

<input type="text" :value="str" @input="handler1">

2. radio 输入框

拆分前:

<input type="radio" name="sex" v-model="gender"><input type="radio" name="sex" v-model="gender">

拆分后:

<input type="radio" name="sex" :checked="gender==='male'" @input="handler2('male')"><input type="radio" name="sex" :checked="gender==='female'" @input="handler2('female')">

备注:上面的input事件,也可以替换成clickchange事件。

3. checkbox 输入框

拆分前:

<input type="checkbox" v-model="agree"/>

拆分后:

<input type="checkbox" :checked="isAgree" @input="handler3"/>

备注:上面的input事件,也可以替换成clickchange事件。

当阻止复选框的默认行为时,只能使用click才能触发
	<input
     type="checkbox"
     name="chk_list"
     :checked="cart.isChecked"
     @click.prevent="changeChange(cart, $event)"
   />

3. TodoList_静态组件

  1. 先把所有的html结构、css样式,都放在App组件中。
  2. 随后拆分成:HeaderListItemFooter组件。
  3. 把:结构、样式,都放在对应的.vue里。

4. TodoList_初始化数据

  1. 需要准备一个todos数组,用于保存多个todo对象。

    todos:[
      {id:'qw7ywqe28',title:'吃饭',done:false},
      {id:'dw3iw92kj',title:'睡觉',done:true},
      {id:'opkmi9s72',title:'学习',done:false},
    ]
    
  2. 观察发现:todos数组,好多组件都要使用,所以我们选择放在App组件中。

    很多组件都用的数据,可以放在他们共同的父组件中,这叫:状态提升(数据提升)。

  3. App组件中:通过props传递给List组件。

    <List :todos="todos"/>
    
  4. List组件中:接收todos数组,使用v-for遍历,生成多个Item组件,同时传递每一个todo对象给Item组件

    <template>
      <ul class="todo-main">
        <Item v-for="t in todos" :key="t.id" :todoObj="t"/>
      </ul>
    </template>
      
    <script>
    	import Item from './Item.vue'
    	export default {
    		name: "List",
    		components:{Item},
    		props:['todos']
    	};
    </script>
    
  5. Item组件接收todo对象,并展示。

    <template>
      <li>
        <label> 
    		<input type="checkbox" :checked="todoObj.done"/>
    		<span>{{todoObj.title}}</span> 
    	</label>
        <button class="btn btn-danger" style="display: none">删除</button>
      </li>
    </template>
    
    <script>
    	export default {
    		name: "Item",
    		props:['todoObj']
    	};
    </script>
    

5. TodoList_添加 todo

  1. 由于数据在App组件中,所以在App中创建一个addTodo方法,专门用于添加todo

  2. App组件中,通过propsaddTodo传给Header组件。

    注意判断重复数据,使用数组的find方法。

    <template>
      <!------------>
      <Header :addTodo="addTodo"/>
      <!------------>
    </template>
    
    <script>
      export default {
        /*****************/
        methods: {
         	// 用于添加一个todo对象
            addTodo(obj){
                // 看一下当前的todos中是否有与要添加的名字重复的todo项
                const result = this.todos.find( item => item.title === obj.title)
                // 如果没有,就添加
                if(result){
                    // 如果重复提示一下
                    alert('不能重复添加')
                }else {
                    // 没有重复,执行添加
                    this.todos.unshift(obj)
                }
             }
        },
        /*****************/
      };
    </script>
    
  3. Header组件中,接收addTodo,需要添加的时候,直接调用即可。

    注意点:我们使用了nanoid这个库,去生成唯一标识。

    <template>
    	<div class="todo-header">
    		<input 
    			type="text" 
    			placeholder="请输入你的任务名称,按回车键确认" 
    			@keyup.enter="handleAdd"
    		/>
    	</div>
    </template>
    
    <script>
    	import {nanoid} from 'nanoid'
      
    	export default {
    		name:'Header',
    		props:['addTodo'],
    		methods: {
    			// 按下回车的回调函数
                handleAdd(event){
                  // 1.获取用户的输入
                  let {value} = event.target
                  if(value.trim()){
                    // 2.将用户输入的title,包装成一个todo对象
                    const todoObj = {id:nanoid(),title:value,done:false}
                    // 3.将todo对象传给App组件
                    this.addTodo(todoObj)
                    // 4.清空输入
                    event.target.value = ''
                  }else{
                    alert('输入不能为空!')
                  }
                }
    		},
    	}
    </script>
    

6. TodoList_删除 todo

  1. 由于数据在App组件中,所以在App中创建一个deleteTodo方法,用于删除某个todo

    methods: {
      /**********/
      deleteTodo(id){
        this.todos = this.todos.filter( t => t.id !== id)
      }
      /**********/
    },
    
  2. App组件中,通过propsdeleteTodo传给List组件。

    <List :todos="todos" :deleteTodo="deleteTodo"/>
    
  3. List组件接收到deleteTodo后,进一步传给Item组件

    <template>
      <ul class="todo-main">
        <Item v-for="t in todos" :key="t.id" :todo="t" :deleteTodo="deleteTodo"/>
      </ul>
    </template>
    
    <script>
    	import Item from './Item.vue'
    	export default {
    		name: "List",
    		components:{Item},
    		props:['todos','deleteTodo']
    	};
    </script>
    
  4. Item组件中,接收deleteTodo,并在需要删除的时候使用

    <template>
      <li>
        <label> 
    		<input type="checkbox" v-model="todo.done"/>
    		<span>{{todo.title}}</span> 
    	</label>
        <button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
      </li>
    </template>
    
    <script>
    	export default {
    		name: "Item",
    		props:['todo','deleteTodo'],
    		methods: {
    			handleDelete(id){
    				if(confirm('确定删除吗?')){
    					this.deleteTodo(id)
    				}
    			}
    		},
    	};
    </script>
    

7. TodoList_勾选 todo

分析:

  • v-model可以实现勾选,虽说没报错,但终归还是修改了props —— 不是很推荐。

  • 更好的做法是:在Item中接收到来自App的方法,实现勾选,具体代码如下:

    1. App组件中,定义一个checkTodo方法,逐层传递给Item(期间要经历List

      <template>
      	<!--------->
      	<List :todos="todos" :deleteTodo="deleteTodo" :checkTodo="checkTodo"/>
      	<!--------->
      </template>
      <script>
      	/*****/
          methods:{
             checkTodo(id){
              this.todos.forEach((item)=>{
                if(item.id === id){
                  item.done = !item.done
                }
              })
            }
          }
          /*****/
      </script>
      
      
    2. List中接收checkOne,随后继续传给Item

    3. 最后在Item组件中使用:

      <input
        type="checkbox"
        :checked="todo.done"
        @click="handleCheck(todo.id)"
       />
      
      <script>
          handleCheck(id){
             this.checkTodo(id)
          }
      </script>
      

8 . TodoList_底部计算

直接使用计算属性,代码如下:

computed:{
  //总数
  total(){
    return this.todos.length
  },
  //已完成的总数
  doneCount(){
    let n = 0
    this.todos.forEach(item => {
      if(item.done){
         n+=1
      }
    });
    return n 
  }
}

9. TodoList_全选 or 全不选

  1. App组件中,定义好一个checkAll方法,用于全选

    <Footer :todos="todos" :clearAllDone="clearAllDone" :checkAllTodo="checkAllTodo"/>
    
    <script>
        methods: {
          checkAllTodo(done) {
            this.todos.forEach((t) => {
              t.done = done;
            });
          },
        },
    </script>
    
  2. Footer组件中

    <input type="checkbox" v-model="isAll"/>
    
  3. isAll改为计算属性

    isAll:{
        get(){
            return this.todos.every((todo)=>{
                return todo.done
            })
        },
        set(checked){
           this.checkAll(checked)
        }
    }
    

10. TodoList_清除已完成

  1. App组件中,通过propsclearAllDone传给Footer组件。

    <Footer :clearAllDone="clearAllDone"/>
    
    <script>
      methods: {
        clearAllDone(){
          this.todos = this.todos.filter( t => !t.done)
        },
      },
    </script>
    
  2. Footer组件中,接收clearAllDone,并使用

    <button class="btn btn-danger" @click="handleClear">清除已完成任务</button>
    
    <script>
      export default {
        name: "Footer",
        props:['clearAllDone','todos'],
        methods:{
          handleClear(){
            if(confirm('确定清除已完成吗?')){
              this.clearAllDone()
            }
          }
        },
      };
    </script>
    

11.强制使闭合代码

//#region 开启位置
  /* const result = this.todos.find( (item) => {
    return item.title === obj.title
  }) */
//#endregion  结束位置

day07

1. 浏览器本地存储

  1. localStorage、sessionStorage可实现浏览器本地存储,它们统称为Web Storage

  2. 内容的格式为:字符串类型的键值对,存储大小一般为:5MB~10MB

  3. 相关API:

    • 存数据

      //如果key存在,则更新其对应的value。
      xxxxStorage.setItem('key', 'value');
      
    • 读数据

      //该方法接收一个key作为参数,返回对应的value。
      var data = xxxxxStorage.getItem('ren');
      
    • 删数据

      //该方法接收key作为参数,会把对应的项删除。
      xxxxxStorage.removeItem('key');
      
    • 清空数据

      //该方法会清空存储中的所有内容。
      xxxxxStorage.clear()
      
  4. 备注:

    1. sessionStorage存储的内容会随着浏览器窗口关闭而消失。
    2. localStorage存储的内容,需要:手动编写代码 或 清空了浏览器所有的缓存,才会消失。
    3. xxxxxStorage.getItem(xxx),如果xxx对应的value获取不到,那么返回值是null
    4. JSON.parse(null)的返回值是null
      在这里插入图片描述

2. TodoList 本地存储版

  1. 需求:刷新页面,关闭浏览器,TodoList列表不清空,依然是之前的数据。

  2. 思路:将数据存储进localStorage中。

  3. 具体操作:在App组件中监视todos数组,只要数组发生变化,就存入localStorage

  4. 代码:

    //......
    data() {
      return {
        //所有要做的事
        todos:JSON.parse(localStorage.getItem('todos')) || []
      }
    }
    //......
    watch:{
      todos:{
        deep:true,
          handler(value){
          	localStorage.setItem('todos',JSON.stringify(value))
        }
      }
    }
    

3. 组件自定义事件

3.1 基本使用

  1. 一种组件间通信的方式,适用于:子组件 ===> 父组件

  2. 使用流程:在【父】中给【子】绑定自定义事件(事件的回调在父组件中)。

  3. 在父组件中,给子组件绑定自定义事件,写法如下:

    <Child @send-toy="getToy"/>
    
  4. 子组件触发自定义事件:

    this.$emit('send-toy',数据)
    

    备注1:多个单词组成的事件名,官方推荐使用kebab-case命名,例如:@hello-world

    备注2:

    • 普通DOM事件(clickmouseenterkeyup事件)靠鼠标键盘的交互去触发事件。

    • 组件的自定义事件,靠vc.$emit('事件名',数据)去触发。


3.2 两种绑定方式

  • 第一种方式:直接在子组件标签上绑定事件

    <Child @send-toy="getToy"></Child>
    
  • 第二种方式:使用ref绑定组件,然后在mounted钩子函数中绑定事件

    <Child ref="c1"></Child>
    <!------>
    
    <script>
      methods: {
        getToy(value){
            console.log('Child组件实例上(vc)的getToy事件被触发了',value)
            // 将收到的玩具,存入自己的toy中
            this.toy = value
        }
      },
      mounted(){
         this.$refs.c1.$on('send-toy',this.getToy)
      }
    </script>
    

3.3 解绑事件

如何解绑自定义事件 —— this.$off('事件名') 解绑指定的事件。
this.$off() 解绑所有的事件

注意1:$off如果不传参数,那就是解绑其身上所有的自定义事件。

注意2:给谁绑的事件,就找谁去触发事件,就找谁去解绑事件。


3.4 native修饰符

当在组件上使用原生的事件时会被当做自定义事件,

//当做自定义事件使用
<Child @click="getToy" />

​ 组件上也可以绑定原生DOM事件,会把原生事件加在组件最外侧元素上,需要使用native修饰符。

//添加native会转变为原生DOM事件
<Child @click.native="nativeGetToy" />

3.5 总结

  1. props可以实现:子 → 父、父 → 子,自定义事件只能:子 → 父
  2. props需要接收,随后使用;自定义事件无需接收,直接触发即可。
  3. 自定义事件,可通过工具查看具体信息,便于调试。

3.6 补充 $once

使用:vm.$once(‘事件名称’,callback)

说明:监听当前实例(vm)中的自定义事件,事件可以由$emit定义,但是只会触发一次,触发后即解除//监听事件被触发

  this.$once('ChildClickFn', arg => {
            console.log('我是用$once监听事件并触发的,参数是:', arg);
        });

4. TodoList_自定义事件版

  1. TodoList中的【添加todo】功能,属于典型的子传父,即:Header 传给App
  2. 把添【添加todo】改成自定义事件版。

5. 一个重要的内置关系

6. 全局事件总线

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

  2. 安装总线:

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

    • 接收数据的组件:给$bus绑定自定义事件,事件的回调留在组件自身。

      methods: {
        test(value){
          //根据需求,编写收到数据后的逻辑
        }
      },
      mounted() {
        //给$bus绑定事件并指定事件的回调,只要$bus的xxx事件被触发,test方法就会调用。
        this.$bus.$on('xxxx',this.test) 
      }
      beforeDestroy(){
       this.$bus.$off('xxxx') //解除单个
       this.$bus.$off(["xxxx", "xxxxx"])//解除多个
       }
      
  • 提供数据的组件:触发$bus对应的自定义事件

    this.$bus.$emit('xxx',数据)
    
  1. 最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件,否则会导致$bus很“重”!

7. TodoList 案例_事件总线

  1. TodoList中的【删除todo】功能,属于孙传祖,即:Item 传给App
  2. 把添【删除todo】改成自定义事件版。

8. 配置代理解决跨域

8.1 方法一

  • vue.config.js中添加如下配置:

  • devServer:{
      proxy:"http://localhost:5000" //代理收到请求后转发的地址(真正有数据的服务器地址)
    }
    

8.2 方法二

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

  • module.exports = {
      devServer: {
      	open:true,//自动打开浏览器
          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
       changeOrigin默认值为true
    */
    

day08

1. github 搜索案例

  • public文件夹中的内容,最终不会参与打包。
  • src文件夹中的内容,最终会经过打包。

2. 自定义指令

  1. 需求:自定义一个v-big指令,功能和v-text类似,但是能把内容放大10倍。

  2. 定义局部指令,定义组件时,追加一个配置 —— directives

    {
        <h4>当前的n值是:<span v-text="n"></span></h4>
        <h4>当前的n值*10<span v-big="n"></span></h4>
        <h4>当前的n值美化后:<span v-very-beauty="n"></span></h4>
            //cut 是全局的
        <h4>当前的str截取第一位后:<span v-cut="str"></span></h4>
    }
    {
      //...
      directives:{
        指令名:回调函数
      }
      //...element是指令所在元素,binding是一个对象
      big(element,,binding){
          console.log('big',element,binding.value)
          element.innerText += binding.value * 10
      },
      'very-beauty'(element,binding){
          element.innerText = binding.value
          element.style.backgroundColor = 'red',
          element.style.color = 'yellow'
      },
    })
    
    

    第二个参数binding的打印

    在这里插入图片描述

  3. 定义全局指令

    Vue.directive(指令名,回调函数)
    
    Vue.directive('cut',function(element,{value}){
      element.innerText = value.slice(0,1)
    })
    
    
  4. 总结:

    1. 指令定义时不加v-,但使用时必须要加v-
    2. 指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名!
    3. 指令回调中的this不是vm也不是vc

3. 插槽

  • 作用:能实现父组件向子组件插入html结构,也是一种组件通信的方式,适用于 父组件 => 子组件
  • 分类:默认插槽、具名插槽、作用域插槽。

6.1 默认插槽

img

父组件中:
        <Category>
          <h2>热门游戏列表</h2>
          <ul>
            <li v-for="g in games" :key="g.id">{{g.name}}</li>
          </ul>
        </Category>
子组件中:
        <template>
          <div class="category">
            <!-- 默认插槽 -->
            <slot></slot>
          </div>
        </template>

6.2 具名插槽

父组件中:
        <Category>
          <h2 slot="title">热门游戏列表</h2>
          <ul slot="content">
            <li v-for="g in games" :key="g.id">{{g.name}}</li>
          </ul>
        </Category>
子组件中:
        <template>
          <div class="category">
            <!-- 具名插槽 -->
            <slot name="title"></slot>
            <slot name="content"></slot>
          </div>
        </template>

6.3 作用域插槽

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

  2. 举例理解:

    压岁钱是孩子的,但是压岁钱怎么花,都能买买什么,由其父亲决定。

  3. 具体编码:

    父组件中:
           <News>
              <!-- 如果News那边是默认插槽,有这么几种写法(写法比较多,推荐大家记住第三种写法): -->
              <!-- <template scope="{newsList}"> -->
              <!-- <template slot-scope="{newsList}"> -->
              <!-- <template v-slot="{newsList}"> -->
              <!-- <template #default="{newsList}"> -->
    
              <!-- 如果News那边是具名插槽(插槽名叫demo),有这么几种写法(推荐记住第三种写法): -->
              <!-- <template scope="{newsList}" slot="demo"> -->
              <!-- <template slot-scope="{newsList}" slot="demo"> -->
              <!-- <template v-slot:demo="{newsList}"> -->
              <template #demo="{newsList}">
                  <ul>
                  <li v-for="n in newsList" :key="n.id">{{n.title}}</li>
                  </ul>
              </template>
            </News>
    
    子组件中:
            <template>
              <div class="news">
                <!-- 具名插槽 -->
                <slot name="demo" a="1" b="2" c="3" :newsList="newsList"></slot>
    
                <!-- 默认插槽 -->
                <!-- <slot a="1" b="2" c="3" :newsList="newsList"></slot> -->
              </div>
            </template>
    
            <script>
              export default {
                name:'News',
                data() {
                  return {
                    newsList:[
                      {id:'ytfdtrasfdtr1',title:'《震惊!某男明星塌房》',isHot:true},
                      {id:'ytfdtrasfdtr2',title:'《毛不易,又来北京啦》',isHot:false},
                      {id:'ytfdtrasfdtr3',title:'《北京持续高温预警》',isHot:false}
                    ]
                  }
                },
              }
            </script>
    

day09

1. 过滤器(了解)

特别注意:过滤器已经在Vue3中移除了,我们只需要了解一下即可。

  1. 概念:对要显示的数据进行特定处理后再显示(适用于一些简单的处理)

  2. 注册(配置)过滤器:

    filters:{
      //upper这个函数何时调用? —— 有人使用这个过滤器的时候。
      //upper这个函数中的this是谁?—— 反正不是vm,也不是vc。
      //upper需不需要写返回值?—— 需要,返回值会呈现在页面上
       //upper收到什么参数?—— 过滤器前方的表达式执行的结果
      upper(value,num){//从第二个参数开始是过滤器传递过来的值
        return value.toUpperCase()
      },
      cut(value){
        return value.slice(0,2)
      }
    }
    
  3. 全局过滤器

    Vue.filter('upper',function(){
       return value.toUpperCase()
    })
    
  4. 使用过滤器:xxx是表达式

    1. 正常使用:{{ xxx | 过滤器}}
    2. 可以传参:{{ xxx | 过滤器(666)}}
    3. 可以串联:{{ xxx | 过滤器1(666) | 过滤器2(777) }}

过滤器回调中的 this 不是 vm ,也不是vc!(这是一个特殊情况)。

2. Vue 插件

  1. Vue插件的本质是什么?—— 本质是一个包含install方法的对象。
  2. Vue插件有什么用?—— 增强你的Vue
  3. 如何安装(应用)一个Vue的插件呢? —— 使用Vue.use(插件)即可。

插件的存在,让Vue的可玩性变得很大,可以集成很多优秀的:组件、指令、过滤器、原型方法 等。

export default {
  /* 
    1.install方法何时调用?—— 当有人使用该插件的时候
    2.install中的this是谁?—— 当前插件对象(几乎不用)
    3.install接收什么参数?—— 第一个参数为Vue构造函数,第二个为传递过来的参数
  */
  install(Vue,n){
    // 注册一个全局组件
    Vue.component('Hello',Hello)

    // 注册一个全局自定义指令
    Vue.directive('big',function(element,{value}){
      element.innerText = value*10
    })

    // 注册一个全局的过滤器
    Vue.filter('cut',function(value){
      return value.slice(0,n)
    })

    // Vue的原型上放置一个方法
    Vue.prototype.welcome = function(){
      alert('欢迎你呀')
    }

    // Vue的原型上放置一个数据
    Vue.prototype.version = 'V1.0'
  }
}
//使用
import plugin from './plugins/index'
Vue.use(plugin,4)

3. 样式绑定

3.1 class 样式绑定



写法 :class="xxx",其中的 xxx 可以是:①字符串、②对象、③数组。

  1. 字符串写法适用于:类名不确定。
  2. 对象写法适用于:个数确定、类名确定,但不确定用不用。—— 用的多!
  3. 数组写法适用于:个数、类名都不确定。
<!-- 动态绑定class样式 —— 第一种写法:字符串写法 -->
<div class="basic" :class="str">你好啊</div>
<!-- 动态绑定class样式 —— 第二种写法:对象写法 -->
<div class="basic" :class="obj">你好啊</div>
<!-- 动态绑定class样式 —— 第三种写法:数组写法 -->
<div class="basic" :class="arr">你好啊</div>
data() {
 return {
    str:'happy',
    obj:{
      atguigu1:false,
      atguigu2:false,
      atguigu3:false,
    },
    arr:['atguigu1','atguigu2','atguigu3']
  }
},

3.2 style 样式绑定

写法 :style="xxx",其中的 xxx 也可以是:①字符串、②对象、③数组。

  1. 字符串写法适用于:属性名、属性值,都不确定。—— 了解即可。
  2. 对象写法适用于:属性名确定,但值不确定。 —— 熟练掌握。
  3. 数组写法适用于:属性名、属性值,都不确定 ——了解即可。
<!-- 字符串写法 -->
   <h2 :style="str">你好啊</h2>
   <!-- 对象写法 -->
   <h2 :style="obj">你好啊</h2>
   <!-- 数组写法 -->
   <h2 :style="arr">你好啊</h2>
data() {
  return {
     str:'color:red',
     obj:{
       color:'purple',
       border:'1px solid black',
       fontSize:'80px',
       backgroundColor:'orange'
     },
     arr:[
       {color:'purple',border:'1px solid black'},
       {fontSize:'80px',backgroundColor:'orange'}
     ]
   }
 },

4. Vue 封装的:动画、过渡

4.1 Vue 封装的动画

  • 第一步:在目标元素外包裹<transition name="xxx">
  • 第二步:编写样式
    • 进入时样式:xxx-enter-active
    • 离开时样式:xxx-leave-active
<transition name="hello1">
 <h1 v-show="isShow">你好啊</h1>
</transition>
@keyframes atguigu {
  from{
    transform: translateX(0);
  }
  to{
    transform: translateX(-100%);
  }
}
.hello1-leave-active {
  animation: atguigu 1s linear;
}
.hello1-enter-active {
  animation: atguigu 1s linear reverse;
}

4.2 Vue 封装的过渡

  • 第一步:在目标元素外包裹<transition name="xxx">

  • 第二步:编写样式

    • 进入样式:

      1. 进入的起点(xxx-enter
      2. 进入的终点(xxx-enter-to
    • 离开样式

      1. 离开的始点(xxx-leave
      2. 离开的终点(xxx-leave-to
  • 给发生变化的元素加:transition: 1s all linear;

<--html-->
<transition name="title">
 	<h1 v-show="isShow">你好啊</h1>
</transition>

h1 {
    background-color: orange;
    font-size: 60px;
    transition: 1s linear;
  }
/* 离开的起点、来的终点 */
.title-leave,.title-enter-to {
  transform: translateX(0);
}
/* 离开的终点、来的起点 */
.title-leave-to,.title-enter {
  transform: translateX(-100%);
}


4.3 集成第三方动画库

  1. 第一步:安装,npm i animate.css

  2. 第二步:引入,import 'animate.css';

  3. 第三步:

    <transition
        enter-active-class="animate提供的进入类名"
        leave-active-class="animate提供的离开类名"
    >
    	<h2 class="animate__animated" v-if="a">你好啊!</h2>
    </transition>
    

5. (拓展)动态组件渲染

component 由is属性决定渲染哪个组件
is中可以写字符串
写字符串的时候,写已注册的组件名

5.1普通使用

<component is="Home"></component>
import Home from './Home.vue'
import Search from './Search.vue'
export default {
   name: "Comp",
   components: { Home, Search },
}

5.2 动态起来

<button @click="compName = 'abc'">展示首页</button>
<button @click="compName = 'Search'">展示搜索页</button>
<component :is="compName"></component>
<script>
   import Home from './Home.vue'
   import Search from './Search.vue'
   export default {
       name: "Comp",
       components: { abc: Home, Search },
       data() {
           return {
               compName: 'abc'
           }
       }
   }
</script>

5.3 自动引入 require.context()

使用:

<template>
    <div class="box">
        <h4>自动引入</h4>

        <!--
            v-for循环对象的时候  value是属性值,key是属性名
            value是组件的配置项,
            key 是组件名
        -->
        <div v-for="(value, key) in compObj" :key="key">
            <component :is="value"></component>
        </div>
    </div>
</template>

<script>
// require.context() 是webpack提供的
// 功能: 匹配获得某个路径下对应类型的所有文件
// 参数:
//      参数一: 要匹配的路径(相对路径)
//      参数二: 是否要进行深度匹配(是否匹配参数一路径下的子路径)
//      参数三: 要匹配的文件
// 返回值: 返回值是一个函数,这个函数不传参会报错,不能直接调用
//          需要传参路径才能被调用

// 如何理解:
// 去'./support'这个路径下匹配所有的.vue文件,false代表不深度匹配,得到一个容器,是一个函数
// 这个函数需要传入路径才能被调用,调用之后可以得到该路径文件的内容
const ctx = require.context('./support', false, /.vue$/)
console.log( ctx('./Home.vue') ) // ctx传入的路径是相对路径,相对于参数一的路径

// 这个容器 ctx 是个函数,它身上由三个方法,我们只关注一个 keys()
// ctx.keys() 拿到容器中两个文件的路径
// console.log(  ctx.keys() )

// let compObj = {}

// ctx.keys().forEach(path => { // 容器文件的路径
//     console.log( ctx(path) )
//     const comp = ctx(path).default // 拿到组件的配置项

//     compObj[comp.name] = comp
// })

// console.log(compObj)

// {
//     组件名: 组件配置项,
//     组件名: 组件配置项
// }

// {
//     Home: Home的配置项,
//     Seach: Search的配置项
// }
export default {
    name: "autoimport",
    computed: {
        compObj() {
            
            let compObj = {}

            // ctx.keys() -> ['./Home.vue', './Search.vue', './Detail.vue']

            ctx.keys().forEach(item => { // item 是容器文件的路径

                const comp = ctx(item).default // 拿到组件的配置项

                compObj[comp.name] = comp
            })

            console.log(compObj)

            return compObj
        }
    }
}
</script>

<style scoped>

</style>

目录结构
在这里插入图片描述

6. $set的使用

作用:给数据添加响应式的数据
vue2 的 API 中 $set

export default {
    data() {
        return {
            name: '张三'
        }
    }
}
// 这里的 name 是响应式数据
this.name = "李四" // 页面会自动更新
this.age = 18 // 期望有一个age的响应式数据,但是这样写并不能把age属性变成响应式的
this.$set(this, 'age', 18) // 这样添加age属性才能变成响应式的
// 底层实现 Object.defineProperty(this, 'age', { get() {}, set(){} })

vue3 中移除了 $set (不需要了),为什么?

目标:为了将数据变成一个响应的

实现:

  • 在vue2中,响应式数据的实现是使用 Object.defineProperty() 这个方法实现的,这个方法是针对某一个对象下的某个属性的,如果在初始化数据的时候,没有这个数据,使用 $set 底层调用 Object.defineProperty() 给当前实例(数据)添加响应式
  • 在vue3中,响应式数据的底层实现是 proxy,当创建出一个数据的时候 new Proxy(obj, { set(){}, get() {} }) , 参数二是配置对象的拦截器的,这里真对的是这个对象,当给这个对象添加属性的时候,例如 obj.inputVisible = true 是会经过 set 方法的,所以不需要单独对 inputVisible 进行处理了

7、nextTick

nextTick接受一个回调函数 可以在DOM更新之后拿取页面的新的DOM

this.$nextTick(()=>{
 在这里获取dom更新后的值
})

8、scoped 的作用

作用:scoped将样式限制在当前组件所有元素和子组件的根标签上
加scoped会发生什么事情?
干了两件事:

  1. 当组件内的style加了scoped会给【当前组件所有标签】和【子组件的根标签】加一个属性 data-v-xxx
    data-v-xxx 这个xxx是一个hash值,唯一的(整个页面唯一的),vue给我们加的
  2. 加scoped这个组件中的style中的css样式会变
    不加scoped的样式
    h2 {
    color: red;
    }
    加了scoped的样式
    h2[data-v-xxx] {
    color: red;
    }
<style lang="scss" scoped>
//修改element-ui中的样式这样直接改不生效   因为样式只是加在组件的根标签上 所有不生效
.el-carousel__button {
   width: 20px;
   height: 20px;
   background-color: red;
   border-radius: 50%; 
}
</style>

如何解决?
使用深度作用选择器,总共有三种

  1. css写法
    格式:
  • .a >>> .b { 样式 }
  • >>> .b { 样式 }
  1. less写法
  • .a /deep/ .b { 样式 }
  • /deep/ .b { 样式 }
  1. scss 和 less 都好使 -------------- 注意: v-deep() 写法是 vue 给我们提供的
  • vue3写法
    • .a::v-deep(.b) { 样式 }
    • ::v-deep(.b) { 样式 }
  • vue2写法
    • .a ::v-deep .b { 样式 }
    • ::v-deep .b { 样式 }
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue2.0 中的 set 是一个函数,它可以用来添加响应式属性。通常,我们在 Vue 实例中定义的 data 对象里,只有事先定义的属性才是响应式的,也就是说,如果要使用一个新属性,我们需要手动地去添加它。当我们需要向对象添加新的属性,并希望这个属性同时是响应式的时,就可以使用 set 函数。 set 函数接受三个参数:目标对象、属性名和属性值。其中,目标对象必须是一个 Vue 实例的 data 对象中的一个已有属性。当我们使用 set 添加新的属性时,Vue 会将这个新属性和参数对象中的属性相互绑定,这意味着在任何一个地方更新这个属性,都会立即更新其他地方的属性。使用 set 函数添加属性的语法为:Vue.set(vm.obj, 'newProp', 123)。 使用 set 可以让我们在运行时动态地为一个对象添加新的属性,并且这个属性是响应式的。这样一来,就可以在模板中使用动态属性来绑定数据,而不用去手动地将属性添加到 data 中,从而提高开发效率。但是,我们也需要注意,在大量使用 set 函数的时候,由于每一个属性都会生成一个新的依赖,会导致内存占用量变大,因此应该尽量减少使用 set 函数的次数。 综上所述,使用 set 函数可以方便地向对象动态添加响应式属性,从而提高代码开发效率。同时,需要注意使用 set 时要避免过度使用导致内存占用量变大问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值