vue基础

163 阅读19分钟

vue基础

数据驱动(双向绑定)

数据驱动是Vue.js最大的特点。在vue中,所谓的数据驱动就是当数据发生变化时,用户界面发生相应的变化,开发者不需要手动的去修改DOM。

比如,我们点击一个button,需要元素的文本做一个 “是/否” 的切换操作,在传统的jQuery中,对于页面修改的流程通常是:对button绑定事件,然后获取文案对应元素的dom对象,最后根据切换来修改dom对象的文本值。

Vue实现数据驱动

vue实现数据双向绑定主要采用数据劫持,配合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的 setter 和 getter ,在数据变动时发布消息给订阅者,触发相应监听回调。

当一个普通 JavaScript 对象传给 Vue 实例来作为它的 data 选项时,vue 将遍历它的属性,用Object.defineProperty 将它们转为getter/setter 。用户看不到 getter/setter ,但是在内部它们让vue追踪依赖,在属性被访问和修改时通知变化。

vue的数据双向绑定将MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的Model的数据变化,通过Compile来解析编译模板指令(vue中用来解析{{}}模板语法),最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到 数据变化 —> 视图更新;视图交互变化(input)—> 数据model变更 双向绑定效果。

getter和setter的理解

当打印出vue实例下的data对象里的属性,它的每个属性都有两个对应的get和set方法。顾名思义,get为取值方法,set为赋值方法。正常情况下,取值和赋值是用 obj.prop 的方式,但是这样做有一个问题,我们如何知道对象的值改变了?

我们可以把get和set理解为function,当我们调用对象的属性时,会进入到 get.属性(){...} 中,先判断对象是否有这个属性,如果没有,那么就添加一个name属性,并给它赋值;如果有name属性,那么就返回name属性。可以把get看成一个取值的函数,函数的返回值就是它拿到的值。

当给实例赋值时,会进入 set.属性(val){...} 中,形参val就是赋给属性的值,在这个函数里做了很多事情,比如双向绑定等等。因为这个值每次都要经过set,其他方式无法对该值做修改。在ES5中,对象原型有两个属性,defineGetterdefineSetter ,专门用来给对象绑定get和set。

虚拟DOM(Virtual DOM)

介绍

渐进式框架: 我们可以用最简单的方式直接导入 vue.js 使用 vue ,随着项目变大,可以集成周边插件使用可以被逐步集成

vue版本:我们学习 vue 的版本是 3 版本

学习的是 选项式 API

官网地址:cn.vuejs.org/

vue.js 下载地址: unpkg.com/vue@3/dist/…

0222

01-vue接入

  1. 先下载 vue.js 下载地址: unpkg.com/vue@3/dist/…
  2. 在 html 文件中导入 vue.js
  3. 创建一个 vue 实例
  4. 将 vue 实例和页面模板进行绑定,让其产生联系

createApp : 用来创建一个 vue 实例用的

mount: 将实例挂载到 id 是 app 的元素上

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
​
  <div id="app">
   <p>{{ message }}</p> 
   <input type="text" v-model='msg'>
   <p>{{ msg }}</p>
  </div>
​
  <script>
    //引入一个名为createApp的工厂函数
    const { createApp } = Vue
    createApp({
      data() {
        return {
        message: 'Hello Vue!',
        msg:'hah',
        msghtml:''
        }
      }
    }).mount('#app')
</script><script>
    const app = Vue.createApp({
      data() {
        return {
        message: 'Hello Vue!',
        msg:'hah',
        msghtml:''
        }
      }
    })
  const vm =app.mount('#app')
</script>

02-模板语法

双大括号语法是 js 表达式,可以取到 data 中的数据

指令:

  1. v-text 渲染普通文本,不会解析标签
  2. v-html 渲染标签样式,可以解析标签
  3. v-bind 用来绑定属性用的 (简写是冒号 :)
  4. v-on 用来绑定事件 用的 (简写艾特符号 @)
  5. v-if 用来进行条件判断,条件成立就添加,否则移除
  6. v-for 用来做循环用的 :[attr]="url" 动态属性,可以将 attr 进行修改,使得 v-bind 绑定不同的属性

v-bind:

绑定属性的时候 可以决定属性是否渲染

<button v-bind:disabled="!isAgree">注册

数据属性值 如果是true false 直接决定 标签属性 是否渲染

数据属性值 如果是null undefined 直接决定标签属性不渲染 等价于 false

数据属性值 如果是0 NAN ' ' 直接决定标签属性渲染 但是 标签属性无值

数据属性值 如果是 非布尔值 非 null undefined 非0 NaN ' '的正常值 都会作为 标签属性值渲染上

03-vue响应式

数据发生改变后不会立即改变页面,先修改虚拟 DOM 中的值,然后有虚拟 DOM 来进行修改真实 DOM

  1. 虚拟 DOM 其实是一个 js 对象

  2. vue 数据发生改变后不会立即更新到真实 DOM 中,而是先更新虚拟 DOM

    1. 当虚拟 DOM 改变后会通过 DIFF 算法将改变后的值更新到真实 DOM 中

      1. DIFF:会比较新老 DOM 找到有改变的地方,只更新有变化的地方,提高性能
      2. nextTick 会在真实 DOM 更新之后调用(如故使用普通获取 无法获取真实dom的值)

04-data要是一个函数要返回一个对象

因为要保证每个组件都有自己独立的数据,具备独立的作用域

写在 data 中的数据是具备响应式的,通过 Proxy 实现

05-计算属性

计算属性的特点:

  1. 计算属性有缓存

  2. 计算属性一上来就会立即执行一次

  3. 如果计算属性中有使用到多个属性,那么这些属性全部都会被监听到只要有一个发生改变那么该函数就会被执行

  4. 计算属性中一定要有一个 return,因为要有一个计算的结果

 5. 计算属性是多个值影响一个值

06-可写的计算属性

可以将计算属性定义为一个对象

该对象中可以设置一个 set 和 一个 get 方法

get 是用户计算结果用的

set 是用来修改计算属性的

07-侦听器

  • immediate 组件创建时刻执行与否

  • deep 深度监听 不推荐使用(非常的消耗性能)

    • 监听的属性是对象的话 不开启deep 对象子属性变化不会触发watch
    • 开启了deep 对象内部所有子属性变化 都会触发watch

针对属性被动 触发 当属性改变的时候触发setter && 两次值不同 可异步 没有return 要求

watch用于观察和监听页面上的vue实例,当你需要在数据变化响应时,执行异步操作,或高性能消耗的操作,那么watch为最佳选择 过滤器 filter

侦听器:

  1. 一上来不会立即执行一次(具有惰性)

  2. 侦听器无需返回值

  3. 支持异步的

  4. 没有缓存

5. 侦听器一次只能监听一个值,一个值影响多个值

计算属性:

  1. 运行就会立即执行一次 (非 惰性)

  2. 计算属性中需要一个返回值

  3. 计算属性不支持异步

  4. 计算属性是有缓存

5. 计算属性能监听多个值,多个值影响一个值

侦听器和计算属性

1.如果一个数据依赖于其他数据,那么把这个数据设计为computed的

2.如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化

计算属性

模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。对于任何复杂逻辑,你都应当使用计算属性。computed

当其依赖的属性的值发生变化时,计算属性会重新计算,反之,则使用缓存中的属性值。 例:

    <div id="example">
      {{ message.split('').reverse().join('') }}
      <p>{{reversedMessage}}</p>
    </div>
    <script>
      Vue.createApp({
        data() {
          return {
            message: 'Hello'
          }
        },
        computed: {
          // 计算属性的 getter
          reversedMessage() {
            // `this` 指向 vm 实例
            return this.message.split('').reverse().join('')
          }
        }
      }).mount('#example')
    </script>

computed的getter函数

在vue中,computed的属性可以被视为是data一样,可以读取和设值。因此,在computed中可以分为getter(读取)和setter(设值),一般情况下,是没有setter的,computed只是预设了getter,也就是只能读取,不可以改变设值。所以,computed默认格式(是不表明getter函数的):

html:

<div>
  message: {{message}}
</div>
<!-- 计算属性 -->
<div>
  计算属性: {{updateMessage}}
</div>
computed: {
  updateMessage(): {
    console.log('计算属性', this.message)
    return this.message
 }
}

等价于

computed: {
  updateMessage: {
     get: function() {
       console.log('计算属性', this.message)
       return this.message
    }
  }
},

在这里,就需要我们注意一下,不是说我们更改了getter中使用的变量(即依赖的属性),就会触发computed的更新,他有一个前提是computed里的值必须要在模板中使用才可以。但是会触发生命周期的updated()

computed中的setter函数

当赋值给计算属性的时候,将调用setter函数。多用于在模板组件中需要修改计算属性自身的值的时候

 <div id ='app'>
    {{ msg1 }}----{{ msg2 }} 
    <button @click="msgf1" >修改出生年份</button> 
    <button @click="msgf2">修改年龄</button>
  </div>
</body>
<script>
  const app = Vue.createApp({
    data() {
      return {
        msg1:'2000',
      }
    },
    computed:{
      msg2:{
        get(){
          return new Date().getFullYear() - this.msg1
        },
        set(value){
          //根据年龄计算出 出生年份 年费改变 会调用get 年龄也会改变
          this.msg1 =  new Date().getFullYear() - value
        }
      }
    },
    methods: {
      msgf1(){
        this.msg1 = 1998
      },
      msgf2(){
        // console.log(2)
        this.msg2 = 30
      }
    },
  })
​
  //挂载
  const vm = app.mount('#app') 

0223

01-class和style

v-bind 该指令是用来绑定属性用的,后面引号中的内容为 js 表达式

绑定 class 可以通过 字符串直接绑定,也可以通过对象和数组进行绑定

如果是通过对象进行绑定的,对象的属性就是 class ,属性对应的值是一个布尔值

布尔值为真就添加该 class 否则不添加

如果绑定 class 之前已经设置了 class 那么 vue 会将这些 class 合并起来

style 绑定可以通过 字符串 对象和数组

<div id="app">
      <div :class="{active:isActive,box:true}">忘记一个很简单</div>
      <!-- <div class="aaa" ,:class="{active}">11122</div> -->
      <div :class="classObj">通过对象绑定class</div>
      <!-- 第一种数组方法 -->
      <div :class="[activearr,boxarr]">1111</div>
      <!-- 第二种数组方法添加 -->
      <div :class="classarr">2222</div>
​
      <!-- ----------------------------------------- -->
      <!-- 直接绑定 -->
      <div :style="{color:activerColor,fontSize:fontSize+'px'}">555555</div>
      <!-- 对象 -->
      <div :style="styleobj">666666</div>
      <!-- 数组 可以把多个对象的值 都传递给一个style -->
      <div :style="[coloraa,styleobj]">666666</div>
    </div>
  </body>
​
  <script>
    const app = Vue.createApp({
      data() {
        return {
          isActive: true,
          classObj: {
            active: false,
            box: true
          },
​
          //第一种数组方法
          activearr: 'active1',
          boxarr: 'box1',
          //第二种数组方法
          classarr: ['active2', 'box2'],
​
          activerColor: 'red',
          fontSize: 30,
​
          coloraa: 'color:red',
          styleobj: {
            // color: 'yellow',
            fontSize: '50px'
          }
        }
      }
    })
    app.mount('#app')

02-条件渲染

v-if v-else-if v-else

是用来判断是否需要渲染元素

具有惰性,默认条件不成立的时候直接会不显示

在切换显示不频繁的时候可以使用 v-if

v-show

是用来判断是否显示元素

非惰性的,默认条件不管是否成立,标签都会被渲染,只是通过 css 让其不显示

在频繁的切换显示隐藏的时候推荐使用 v-show

03-列表渲染 for问题

v-for

可以遍历 数字 一段字符串 一个数组 一个对象

遍历数字 v-for='num in 10' 此时就会执行 10 次 第一次的值是 1

遍历字符串 v-for='str in '你好世界'' 你 好 世 界

遍历一个数组无需注意其他

遍历对象 v-for='(值,属性,索引) in {name: "aaa", age: 18}'

v-for 使用的时候一定要加一个 key 属性,而且该 key 属性还要是唯一的

因为 vue 使用的是虚拟 DOM ,当我们再前面添加一个内容的时候,会在虚拟 DOM

的前面添加该内容,但是渲染成真是 DOM 后,原来的标签位置不会改变,只会在

最后位置新增一个新的标签,如果要解决该问题,可以在使用 v-for 的时候添加一个 key 属性

v-if 和 v-for 一起使用

不推荐 一起使用,因为优先级不同

在 vue2 中 for 优先级高于 if(不管遍历多少次,我就需要判断多少次)

在 vue3 中 if 优先级高于 for (只要条件不成立,压根就不会执行循环)

04-事件处理

内联事件处理器:事件被触发时执行的内联 JavaScript 语句 (与 onclick 类似)。

就是 @click='count++'

方法事件处理器:一个指向组件上定义的方法的属性名或是路径。

就是 @click='add'

修饰符:

.self 是将事件指明只有点击自身的时候才会被触发 .capture触发内部事件时,先执行外部事件 .stop 是修饰符,该修饰符是用来阻止冒泡用的 .prevent 是用来阻止默认事件用的 .once 设置该事件只被触发一次

.passive @scroll.passive="myScroll" 用来提升移动端性能用的

键盘事件,修饰符

@keyup.enter

  • .enter
  • .tab
  • .delete (捕获“Delete”和“Backspace”两个按键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

05-表单处理

v-model 是双向数据绑定,可以将输入框的内容和 data 中定义状态进行关联

修饰符:

.lazy 在 "change" 事件后同步更新而不是 "input" .number 将输入内容转换为数字 (一般是需要正则判断数字 如手机号 金额等东西) .trim 用来去除首位空格,不能去除中间空格

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件: input['text'] 和 textarea 元素使用 value property 和 input 事件; checkbox 和 radio 使用 checked property 和 change 事件; select 字段将 value 作为 prop 并将 change 作为事件

<label for="">性别</label>
      男<input type="radio" name="sex" value="0" v-model="sex" /><input type="radio" name="sex" value="1" v-model="sex" />
      <p>{{sex}}</p>
​
      <input type="text" v-model="username" />
      <p>{{username}}</p>
​
      <textarea v-model="comment"></textarea>
      <p>{{ comment }}</p>
​
      <!-- 复选框 复选框多选框 -->
      <label for="">兴趣</label>
      <input type="checkbox" name="hoo" value="篮球" v-model="hoos" />
      <input type="checkbox" name="hoo" value="足球" v-model="hoos" />
      <input type="checkbox" name="hoo" value="台球" v-model="hoos" />
      <input type="checkbox" name="hoo" value="排球" v-model="hoos" />
      <p>{{hoos}}</p>
      <!-- 复选框 -->
      <input type="checkbox" id="checkbox" name="hooaa" v-model="toggle" true-value="同意" false-value="不同意" />
      <label for="checkbox">{{ toggle }}</label>
      <p>{{hooa}}</p><!-- 下拉 -->
      <!-- 多选 multiple-->
      <select name="books" multiple v-model="books" id="">
        <option value="122">2222</option>
        <option value="233">333</option>
        <option value="113">444</option>
        <option value="133">555</option>
        <option value="145">666</option>
      </select>
      <p>{{books}}</p>
//小案例。。。。。。。。。。。。。。。。。。。。。。。。小案例。。。。。。。。。。。。。。。。。。。。。。。。。。。
      <input type="checkbox" name="agree" v-model="isAgree" />我已经自习阅读并同意条款内容
      <br />
      <button :disabled="!isAgree">注册</button>
    </div>
  </body>
  <script>
    const app = Vue.createApp({
      data() {
        return {
          username: '张三',
          sex: '',
          comment: '',
          hoos: [],
          toggle: '不同意',
          books: [],
          isAgree: ''
        }
      }
    })
    app.mount('#app')

06-生命周期

选项式 API 中有 8 个生命周期

// 在组合式 API 中,setup 会替代掉 beforeCreate,created 两个生命周期
        beforeCreate () {
            console.log('创建之前');
        },
        created () {
            console.log('创建完成');
            // 老程序员,可能会在这里进行数据请求
        },
        beforeMount () {
            console.log('挂载之前');
        },
        mounted () {
            console.log('挂载完成');
            // 数据请求写在这里
        },
        beforeUpdate () {
            console.log('更新之前');
        },
        updated () {
            console.log('更新完成');
        },
        beforeUnmount () {
            console.log('卸载之前');
        },
        unmounted () {
            console.log('卸载完成');
            // 清除一些影响性能的函数或者说监听的事件
        },

0224

01-ref

ref:

ref 可以用来标记一个或者多个元素,目的是方便我们操作原生 DOM 元素

ref 也可以添加在组件上,可以获取到对应组件实例

02-注册局部组件

  1. 声明一个组件
  2. 通过 components 注册一个组件
  3. 使用 该组件
// 1. 声明一个组件
    // 组件中的选项,和我们之前 app 中的选项是一模一样的
    const myCom = {
        // 组件模板
        template: `<h1>{{msg}}</h1>`,
        // 组件的数据
        data () {
            return {
                msg: '有些闲言碎语 ,之所以听了格外难受,是因为他们说的是对的。'
            }
        },
        // 组件中的函数
        methods: {
​
        },
    }
​
​
    const app = Vue.createApp({
        data () {
            return {}
        },
        // 2. 注册局部组件
        components: {
            //  这里可以注册组件,可以注册多个组件
            // 大写字母开头是可以使用的
            Mycom: myCom
            // 全部小写是可以使用的
            // mycom: myCom
            // 连接符的方式是可以使用的
            // 'my-com': myCom
            // 大驼峰不能使用(单页面开发时可用而且是常用)
            // MyCom: myCom
            // 小驼峰不能使用
            // myCom: myCom
        }
    })
<div id='app'>
​
        <!-- 3. 使用组件 -->
        <!-- 自定义的组件,可以单标签写法也可以支持双标签写法 -->
        <!-- <Mycom></Mycom> -->
        <Mycom />
​
    </div>

03-注册全局组件

  1. 通过 app.component 函数来进行注册组件

    该 component 有两个参数,分别是 组件名称 和 组件描述

  2. 使用组件

 // 直接注册组件
    // 1. 注册一个全局组件
    // 参数1:组件的名称
    // 参数2:组件的描述
    app.component('my-button', {
        template: `<button @click='count++'>按钮 {{count}}</button>`,
        data () {
            return {
                count: 0
            }
        },
    })
<div id='app'>
        <button>军平的按钮</button>

        <!-- 2. 使用组件  -->
        <my-button></my-button>
        <my-button></my-button>
        <my-button></my-button>
        <my-button></my-button>
    </div>

04-组件模板解析

<ul>,<ol>,<table> 和 <select> 内部元素一定要是 li tr option

否则会将内部元素提取到外部去

通过 is 属性解决该问题 <tr is="vue:row"></tr> row 为组件名称

05-props 传值

父给子组件传值

  1. 在使用组件的时候需要给组件添加属性


  <cart msg="使用的时候传递的属性" num="10" :age="18" :is="true" 
  
  :tit="title" :isshow="isShow"></cart>

  1. 在子组件中通过 props 选项进行接收
app.component('cart', {
      template: '#cart',
    // 2. 在组件内部添加一个 props 接收父组件中传递过来的属性
      props: ['msg', 'num', 'age', 'tit', 'isshow']
    })
  1. 使用属性

    <!-- 定义组件模板 -->
    <template id="cart">
        <!-- 组件中最好是只有一个根标签 -->
        <div v-show="isshow" class="cart">
              <h1>标题</h1>
      <p>新闻内容</p>
      <!-- msg 就是 通过 props 接收的数据 -->
      <p>{{msg}} -- {{num + 24}}</p>
      <p>age: {{ age + 5 }}</p>
      <h1>{{tit}}</h1>
    </div>
    </template>
    

06-单向数据流

vue 所谓的单向数据流,就是子组件只能使用父组件中的数据,但是不能修改

如果需要修改

> 1. 将值复制一份,然后修改自己复制的值
> 2. 告诉父组件我要修改什么数据,由父组件来进行修改

07-属性验证

子组件可以接收父组件传递的数据,且可以设置要求传递数据的类型

只有符合类型要求的数据才可以传递,否则会有一个警告

msg: [Number, String], 可以设置接收数据类型为多个

required: true 可以设置属性为必传项

default: 10, 设置属性的默认值,如果不传就使用默认的值

props: {
            // 属性验证,要求属性的类型一定要和指定的类型相同,否则会有警告信息
            count: Number,
            isshow: Boolean,
            // 设置可以接收数字和字符串类型,其他类型不可以接收
            msg: [Number, String],
            message: {
                type: [Number, String, Object],
                // 设置该属性为必填项
                required: true
            },
            price: {
                // 配置默认值,当父组件不给传值的时候就使用默认值,传了就用父组件传递的值
                default: 10,
                type: Number
            },
            obj: Object,
            arr: Array,
            fn: Function
        }

注意点

组件中的

组件模板template 根节点只能有一个 如果出现多个 建议用一个节点包起来

0227

01-自定义事件

所谓的自定义事件就是子组件给父组件传递值

  1. 在父组件中先定义一个接收数据的方法
  2. 使用子组件的时候监听我们自定义事件
  3. this.$emit('calc', ran) 触发自定义事件,并且携带一个参数

如果是多个参数 用arguments 接受 如果emit 和 自定义事件都传值了 emit的值用$event接受

02-依赖注入

所谓的依赖注入其实就是祖先组件给后代组件传递参数

  1. 首先在祖先组件中通过 provide 将属性暴露出去
  2. 在后代组件中通过 inject 将数据注入到组件中

03-属性透传

所谓的属性透传就是在自定义的组件,使用的时候可以写一些如 id class 或者 style 等属性,这些属性会被直接添加到组件的根标签中,如果有多个根标签就无法直接使用属性透传,可以使用 $attrs 来进行设置将属性添加在哪里,如果你通过 props 进行了接收某些属性,那么这些属性将不能被透传

04-插槽

插槽其实是用来做内容分发用的,可以在组件中预留好插槽,在使用组件的时候,有些内容可能是有添加,有些时候可能是不需要显示的,对于这些内容我们就可以使用插槽,提前预留好对应的位置。

  1. 先在组件中添加一个 slot 标签,用来占位
  2. 使用组件的时候用双标签写法,内部可以放子标签,那么子标签就会被加在 slot 中

如果有多个子标签,那么这些子标签都会被渲染,但是如果你想要一个标签加到一个 slot 中那么我们可以使用具名插槽

    具名插槽 变种 后的作用域插槽
<div id='app'>
        <navcom title="首页">
            <!-- 
                使用的时候我们可以在插槽名称后面,定义一个变量接收值
                该变量名称是我们自己起的
             -->
            <template v-slot:left="data">
                <span class="back">返回 {{data.count}}</span>
            </template>
            <template #right="obj">
                <span class="login">{{obj.title}}</span>
            </template>

        </navcom>

    </div>
</body>
<template id="nav">
    <div class="nav">
        <!-- 1. 在 slot 标签中添加自定义属性,将值传递过去 -->
        <slot :mycount="10" message="你好世界" :count="count" name="left"></slot>
        <h4>{{title}} -- {{count}}</h4>
        <slot title="你笑起来真好看" name="right"></slot>
    </div>
</template>

05-具名插槽

所谓的具名插槽其实就是可以给 slot 标签添加一个 name 属性,

在使用组件的时候外层要是一个 template 且配合 v-slot 指令进行设置对应的名称

<template v-slot:left>
    <span class="back">返回 {{count}}</span>
</template>

v-slot 的简写是 #

06-作用域插槽

所谓的作用域插槽其实就是我们在 app 模板中使用组件中的数据

我们可以在 slot 组件中添加自定义属性

 <slot :mycount="10" message="你好世界" :count="count" name="left"></slot>

然后在使用插槽的时候进行接收

使用的时候我们可以在插槽名称后面,定义一个变量接收值该变量名称是我们自己起的

<template v-slot:left="data">
    <span class="back">返回 {{data.count}}</span>
</template>

07-异步组件

异步组件,是针对一些不太确定什么时候可以获取到的组件可以使用异步组件如一个组件是从服务器请求获取到的组件,那么该组件我们不能 确定他什么时候可以获取成功,不知道什么时候可以显示,那么我们就可以使用异步组件,在请求成功后返回即可

Vue.defineAsyncComponent 用来定义一个异步组件用的

08-自定义指令

在系统指令无法满足我们开发需求的时候,我们可以自定义一个指令

directives 自定义指令的选项

binding.value 获取指令后面的值 binding.arg 获取指令的属性 binding.modifiers 获取到修饰符

directives: {
            // 自定义指令的时候不需要加 v-,在标签中使用的时候直接 v-foc 即可
            foc: {
                // 在绑定元素的 attribute 前
                // 或事件监听器应用前调用
                created (el, binding, vnode, prevVnode) {
                    // 下面会介绍各个参数的细节
                },
                // 在元素被插入到 DOM 前调用
                beforeMount (el, binding, vnode, prevVnode) { },
                // 在绑定元素的父组件
                // 及他自己的所有子节点都挂载完成后调用
                mounted (el, binding, vnode, prevVnode) {
                    console.log(vnode, prevVnode);
                    setTimeout(() => {
                        el.focus()
                    }, 2000)
                    // binding.value 获取指令后面的值
                    // binding.arg 获取指令的属性
                    // binding.modifiers 获取到修饰符
                    // console.log(binding);
                    el.style.color = binding.value
                    if (binding.modifiers.num) {
                        // 有该修饰符
                        // 阻止默认事件
                    }
                    if (binding.arg == 'title') {
                        el.title = binding.value
                    }

                },
                // 绑定元素的父组件更新前调用
                beforeUpdate (el, binding, vnode, prevVnode) { },
                // 在绑定元素的父组件
                // 及他自己的所有子节点都更新后调用
                updated (el, binding, vnode, prevVnode) { },
                // 绑定元素的父组件卸载前调用
                beforeUnmount (el, binding, vnode, prevVnode) { },
                // 绑定元素的父组件卸载后调用
                unmounted (el, binding, vnode, prevVnode) { }
            }
        }

09-全部指令

v-text:直接渲染字符串,不做标签解析

v-html: 渲染且解析字符串内的元素及样式

v-show: 通过 CSS 实现显示或隐藏元素

v-if:通过添加或移除一个标签实现显示隐藏

v-else

v-else-if

v-for: 循环遍历数组或者对象或者数字,记得加 key 哟

v-on: 监听事件用的,绑定事件用的

v-bind: 添加绑定属性用的

v-model:双向数据绑定

v-slot:使用具名插槽时用的

v-pre: 跳过编译直接渲染

v-once: 只渲染一次,后期更新不做改变

v-memo: 添加依赖项,只有依赖项改变时才会重新渲染

v-cloak: 当没有准备好显示的时候先将其隐藏掉,准备后直接渲染

10-动态组件

可以借助 component 组件配合 is 属性实现,组件的动态切换,is 属性的值就是组件的名称

keep-alive 是用来做组件缓存用的,其有 3 个属性, include exclude :max

include :包含,只有包含的组件才会被缓存,其余组件全部都不会被缓存。对应的值是定义组件是的 name 属性的值

exclude :排除,写在排除中的组件将不会被缓存

:max:配置最大缓存数量

0228

01-动画过度

transition 将需要添加动画和过渡的标签放在其内部,会增加不同状态下的 class,里面只能放一个根标签 transition-group 其功能和 transition ,其内部可以放多个根标签

属性

appear 规定该过度一运行就会立即执行一次

name 是用来定义 class 开头的名称

02-teleport 传送

teleport 用来做传送用的,to 属性是指定我们将要传送的内容传送到什么地方去,该属性可以

是标签的名称,也可以是一个 id ,尽可能的使用 id ,不仅可以传递到当前组件中,还可以

传递到组件的外部,或者 app 的外部

teleport 通常会使用在弹出层,如广告,或者活动

03-mixin 混入

mixin 是可以将公用的属性和方法放在一个混入中

  1. 组件自身的数据优先级会高于混入
  2. 对于函数而言,组件自身的函数优先级会高于混入
  3. 对于计算属性而言自身优先级高于混入
  4. 对于生命周期而言,混入的会高于自身的

04-获取父组件和根组件

this.$parent 获取父组件实例,可以获取而且可以修改其内容,但是不建议直接操作父组件

this.parent.parent.parent 也可以获取到父组件的父组件

this.$root 获取到根组件

05-组合式API

所谓的组合式API其实就是在原来选项式API的基础上做的升级

选项式API 使用的过程是比较分散的,比如我们会有 数据的选项、函数选项、侦听器选项和计算属性选项

所以会导致我们数据的管理比较复杂,因为数据有可能会在多个选项中使用,那么如果一旦发生错误的时候排错会比较麻烦

组合式API 使用的是统一管理,可以将一个数据的 所有选项放在一起,当有发现问题的时候,只需要在这一个去榆中排查即可

06-ref 基本类型具备响应式

ref:让基本数据类型具备响应式,也可以让引用类型具备响应式

const { ref } = Vue 
let name = ref('张一')
// 修改通过 ref 创建的数据时需要加一个 .value 属性才可以
name.value = '张三'// 会将   '张一'  ->   proxy({value: '张一'})

07- reactive 引用类型具备响应式

会给该对象添加一个 proxy 进行代理,监听数据的改变

<body>
    <div id="app">
      <div>
        {{ state.count }}
        <button @click="state.count++">增加</button>
      </div>
​
      <div>
        {{ arr }}
        <button @click="addArrItem">点击增加内容</button>
      </div>
    </div>
  </body>
  <script>
    // reactive 让引用类型具备响应式
    const { reactive } = Vue
    const app = Vue.createApp({
      setup(props, context) {
        // let state = reactive({
        //   count: 100
        // })
​
        let arr = reactive([1, 2, 3])
​
        function addArrItem() {
          arr.push('js')
        }
​
        return {
          state,
          arr,
          addArrItem
        }
      }
    })
    app.mount('#app')
​

08- readonly 定义只读数据

导入 readonly 在定义数据的时候使用 readonly 进行嵌套

readonly 是用来定义只读数据用的,如果去修改,那么会给一个警告

0301

01- toRefs

toRefs 是在 Vue 中解构的一个方法,该方法主要的作用是让解构出的数据具备响应式

02- toRef

toRefs 是在 Vue 中解构的一个方法,该方法主要的作用是在解构的时候,有些属性不确定有还是没有,对于这种属性如果咱直接使用,再次赋值的时候会报错。此时可以使用 toRef 进行解构,如果该数据不存在的时候,会自动创建一个空的该数据

ref属性:用来标记DOM元素,或者标记组件用的

$refs:属性是用来获取被 ref 标记的元素或组件

ref方法:让基本类型的数据具备响应式

toRefs方法:让解构出的数据具备响应式

toRef方法:解构时如果没有该属性就会自动创建该属性

03- setup 参数

props: 使用时,一定要在选项中先声明接收哪些参数,然后我们在 setup 中的 props 才能够正常使用

context: 上下文,该对象中有属性和方法,因为在 setup 中无法使用 this (因为在组合式API中 setup 会替代掉生命周期函数创建之前和创建完成,那么所以在 setup 被掉用的时候 ,实例还没有被创建完成所有 this 指的是 window )

04- context-attrs

该 attrs 和在选项式API中的 $attrs 是同一个对象,我们可以在 setup 中直接操作属性透传过来的值,同样在组件定义的时候,如果有多个根标签还是 v-bind 直接绑定即可,要是一个根标签,那么属性透传会直接加载到该标签上

05- context-slot

h 函数,该函数是用来创建虚拟 DOM 用的,其内部需要三个参数

参数一: 标签名称(html标签名)

参数二: 标签属性(标签中可以添加的任意属性)

参数三: 标签的内容(内容是一个数组,该数组中可以放字符串也可以放插槽)

context.slots.login(), // 使用具名插槽

context.slots.default() // default 是用来获取没有添加名称的插槽标签

06- context-emit

context.emit 同 this.$emit 方法功能一致,因为在 setup 中无法使用 this ,所有要触发自定义事件时,可以使用 context.emit 进行触发,触发时有两个参数,第一个是触发的事件名称,第二个是要传递过去的数据

07- context.expose

关闭当前组件实例,不提供给任何组件

在 setup 使用 ref 属性

  1. 先通过 ref 函数创建一个数据
  2. 将该数据通过 return 暴露出去
  3. 给标签或者组件添加该 ref ,注意ref前面不要加 :
  4. 在 setup 中就可以直接通过定义的 ref 属性进行访问

08- setup 计算属性

在 setup 中计算属性和选项式 API 功能一样,使用时需要在 vue 中进行解构使用

09- setup 侦听器

该侦听器功能和选项式 API 功能一样,但是使用的时候需要先解构,如果需要监听多个属性时,可以将第一个参数改为数组的方式

         // 使用侦听器
         // watch(price, (currenValue, prevValue) => {
         //     // 这里是侦听器中的业务逻辑
         //     console.log(currenValue, prevValue);

         //     vip.value = currenValue * 0.8
         //     svip.value = currenValue * 0.5
         // })

         // 侦听器可以通过配置数组的方式来侦听多个属性
         // currenValue 在侦听多个属性时会是一个 最新的数组
         // prevValue 在侦听多个属性时会是一个 最新的数组
         // 侦听的属性只要有一个发生改变,那么后面的回调函数就会立即执行
         watch([price, name], (currenValue, prevValue) => {
             console.log(currenValue, prevValue);

         })

10- watchEffect

watchEffect 非惰性的侦听器,更加抽象显示函数内的变量,函数内部的所有变量都会被监听,只要有一个发生改变该,侦听器就会被调用执行 (谨慎使用)

// watchEffect 非惰性的侦听器,更加抽象显示函数内的变量
         // 函数内部的所有变量都会被监听,只要有一个发生改变该
         // 侦听器就会被调用执行  (谨慎使用)
         watchEffect(() => {
             // 非惰性,一上来就会立即执行一次
             // 可以监听多个属性
             // 可以做深度监听
             console.log('watchEffect: ', price.value);
             console.log('watchEffect: ', name.value);
         })

11- setup 生命周期

在 setup 中使用生命周期需要先在 Vue 中进行解构然后才能使用

在组合式API 中 setup 会替代掉 beforeCreate 和 created,所以我们在组合式中常见的生命周期有 7 个

const { onBeforeMount, onMounted, onBeforeUpdate, onUpdated } = Vue


            onBeforeMount(() => {
                console.log('挂载之前调用');
            })

            onMounted(() => {
                console.log('挂载完成');
            })

            onBeforeUpdate(() => {
                console.log('更新之前');
            })

            onUpdated(() => {
                console.log('更新完成');
            })

## 12- 依赖注入

> 依赖注入功能和选项式API一致,使用的时候我们可以通过 解构 出两个函数provide 和 inject直接调用
>
> provide('msg', msg) provide(发射出去的标识符, 发射出去的具体内容)
>
> const message = inject('msg') inject(发射时的标识符)