Vue3.3指北(三)

news2024/11/16 13:06:33

Vue3.3指北

  • 1、Vue2和Vue3
    • 1.1、 Vue2 选项式 API vs Vue3 组合式API
    • 1.2、Vue3的优势
  • 2、组合式API - setup
    • 2.1、setup选项
    • 2.2、setup中写代码的特点
    • 2.3、`<script setup>`语法糖
    • 2.4、props和context
  • 3、组合式API - reactive和ref函数
    • 3.1、reactive
    • 3.2、ref
    • 3.3、reactive 对比 ref
  • 4、组合式API - computed
  • 5、组合式API - watch
    • 5.1、侦听单个数据
    • 5.2、侦听多个数据
    • 5.3、immediate
    • 5.4、deep
  • 6、组合式API - watchEffect
    • 6.1、基本使用
    • 6.2、watchEffect的其他参数
      • 6.2.1、stop停止侦听
      • 6.2.2、onInvalidate消除副作用
  • 7、组合式API - 父子通信
    • 7.1、父传子
    • 7.2、子传父
  • 8、组合式API - 模版引用
    • 8.1、获取真实dom对象
    • 8.2、defineExpose
  • 9、组合式API - provide和inject
    • 9.1、provide
    • 9.2、inject
    • 9.3、跨层传递数据
    • 9.4、跨层传递方法
  • 10、Vue3.3 新特性-defineOptions
  • 11、Vue3.3新特性-defineModel
  • 12、高阶API - mixin
  • 13、高阶API - 自定义指令
    • 13.1、自定义指令语法
      • 13.1.1、自定义指令配置项
      • 13.1.2、使用自定义指令
      • 13.1.3、自定义指令配置项使用
      • 13.1.4、自定义指令__指令的值
  • 14、高阶API - teleport传送门

视频参考教程: 2021年Vue3.0全家桶全系列精讲
随笔记源码: 逍遥的人儿 / KuangStudyVue3
在这里插入图片描述

1、Vue2和Vue3

1.1、 Vue2 选项式 API vs Vue3 组合式API

<!--选项式API-->
<script>
export default {
  data(){
    return {
      count:0
    }
  },
  methods:{
    addCount(){
      this.count++;
    }
  }
}
</script>
<!--组合式API-->
<script setup>
import { ref } from 'vue'
const count = ref(0)
const addCount = ()=> count.value++
</script>

组合式特点:

  1. 代码量变少
  2. 分散式维护变成集中式维护

1.2、Vue3的优势

在这里插入图片描述

2、组合式API - setup

2.1、setup选项

  • 写法
<script>
  export default {
    setup(){
      
    },
    beforeCreate(){
      
    }
  }
</script>
  • 执行时机

在beforeCreate钩子之前执行

在这里插入图片描述

2.2、setup中写代码的特点

  • setup函数中写的数据和方法需要在末尾以对象的方式return,才能给模版template使用
<script>
  export default {
    setup(){
      const message = 'this is message'
      const logMessage = ()=>{
        console.log(message)
      }
      // 必须return才可以
      return {
        message,
        logMessage
      }
    }
  }
</script>

2.3、<script setup>语法糖

script标签添加 setup 标记,不需要再写导出语句,默认会添加导出语句

<script setup>
  const message = 'this is message'
  const logMessage = ()=>{
    console.log(message)
  }
</script>

示例:我们在模板里面应用 setup() 函数里面的东西

<script>
    // 1.创建Vue的实例对象
    const app = Vue.createApp({

        setup(props,context) {
            const message = 'this is message';
            const logMessage = ()=>{
                console.log(message);
            };
            return {
                message,
                logMessage
            }
        },

        // 我们在模板里面应用 setup() 函数里面的东西
        template: `
        <h1>{{message}}</h1>
        <button @click="logMessage">点击触发</button>`
    });

app.mount('#app');
</script>

2.4、props和context

  • setup 里接收的参数是 propscontext
// 声明时props和setup同级,可以通过以下方式对父组件传递的参数在props中声明
props:{
    msg:String,
    name:String
},
  • context 上下文包括 attrsemitslots
    • attrs :接收在父组件传递过来的,并且没有在props中声明的参数
    • emit :子组件对父组件发送事件
    • slots :插槽

在vue2中,子对父发送事件采用this.$emit对父组件发送事件,在vue3中子组件对父组件发送事件采用context.emit发送事件

import { ref } from 'vue';
 
export default {
  props: {
    message: String
  },
  setup(props, context) {
    const count = ref(0);
 
    // 使用props
    console.log(props.message);
 
    // 使用context
    console.log(context.attrs);
    console.log(context.slots);
    console.log(context.emit);
 
    return {
      count
    };
  }
};

在上面的示例中,我们使用了propscontext参数来获取组件的属性、插槽和触发事件的方法。

需要注意的是,setup()函数在组件初始化期间只会执行一次,并且在datacomputed等选项之前执行。

3、组合式API - reactive和ref函数

3.1、reactive

  • 接受对象类型数据的参数传入并返回一个响应式的对象
<script setup>
 // 导入
 import { reactive } from 'vue'
 // 接收对象类型
 const state = reactive({
   msg:'this is msg'
 })
 const setSate = ()=>{
   // 修改数据更新视图
   state.msg = 'this is new msg'
 }
</script>

<template>
  {{ state.msg }}
  <button @click="setState">change msg</button>
</template>

3.2、ref

  • 接收简单类型或者对象类型的数据传入并返回一个响应式的对象
    • 让基础类型的数据具备响应式(有点像v-model双向绑定数据的感觉)
<script setup>
 // 导入
 import { ref } from 'vue'
 // 执行函数 传入参数 变量接收
 const count = ref(0)
 const setCount = ()=>{
   // 修改数据更新视图必须加上.value
   count.value++
 }
</script>

<template>
  <button @click="setCount">点击增加</button>
</template>

Tips:

  • 需要注意的是使用ref参数类型修改数据必须加上 .value

3.3、reactive 对比 ref

相同点:

  • 都是用来生成响应式数据

不同点

  1. reactive不能处理简单类型的数据
  2. ref参数类型支持更好,但是必须通过.value做访问修改
  3. ref函数内部的实现依赖于reactive函数

在实际工作中的推荐

  • 推荐使用ref函数,减少记忆负担

4、组合式API - computed

计算属性基本思想和Vue2保持一致,组合式API下的计算属性只是修改了API写法

  • computed()方法返回值是个计算属性ref对象,在模板中使用也是会自动解包的
  • 它的参数是一个回调函数,也就是箭头函数
<script setup>
// 导入
import {ref, computed } from 'vue'
// 原始数据
const count = ref(0)
// 计算属性
const doubleCount = computed(()=>count.value * 2)

// 原始数据
const list = ref([1,2,3,4,5,6,7,8])
// 计算属性list
const filterList = computed(item=>item > 2)
</script>

5、组合式API - watch

  • 侦听一个或者多个数据的变化,数据变化时执行回调函数
  • 三个参数
    • 第一个参数是:选择要监听的属性选择要监听的属性
    • 第二个参数是:设置的回调函数。即监听到变化时应该执行的函数
    • 第三个参数是配置项
      • immediate 控制立刻执行
      • deep开启深度侦听

5.1、侦听单个数据

<script setup>
  // 1. 导入watch
  import { ref, watch } from 'vue'
  const count = ref(0)
  // 2. 调用watch 侦听变化
  watch(count, (newValue, oldValue)=>{
    console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`)
  })
</script>

5.2、侦听多个数据

  • 侦听多个数据,第一个参数可以改写成数组的写法
<script setup>
  // 1. 导入watch
  import { ref, watch } from 'vue'
  const count = ref(0)
  const name = ref('cp')
  // 2. 调用watch 侦听变化
  watch([count, name], ([newCount, newName],[oldCount,oldName])=>{
    console.log(`count或者name变化了,[newCount, newName],[oldCount,oldName])
  })
</script>

5.3、immediate

在侦听器创建时立即出发回调,响应式数据变化之后继续执行回调

<script setup>
  // 1. 导入watch
  import { ref, watch } from 'vue'
  const count = ref(0)
  // 2. 调用watch 侦听变化
  watch(count, (newValue, oldValue)=>{
    console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`)
  },{
    immediate: true
  })
</script>

5.4、deep

  • 通过watch监听的ref对象默认是浅层侦听的,直接修改嵌套的对象属性不会触发回调执行,需要开启deep
<script setup>
  // 1. 导入watch
  import { ref, watch } from 'vue'
  const state = ref({ count: 0 })
  // 2. 监听对象state
  watch(state, ()=>{
    console.log('数据变化了')
  })
  const changeStateByCount = ()=>{
    // 直接修改不会引发回调执行
    state.value.count++
  }
</script>

<script setup>
  // 1. 导入watch
  import { ref, watch } from 'vue'
  const state = ref({ count: 0 })
  // 2. 监听对象state 并开启deep
  watch(state, ()=>{
    console.log('数据变化了')
  },{deep:true})
  const changeStateByCount = ()=>{
    // 此时修改可以触发回调
    state.value.count++
  }
</script>

6、组合式API - watchEffect

watchEffect 也是一个帧听器,是一个副作用函数。 它会监听引用数据类型的所有属性,不需要具体到某个属性,一旦运行就会立即监听,组件卸载的时候会停止监听。

6.1、基本使用

<template>
  <div>
    <h2>{{ counter }}</h2>
    <button @click="addCounter">+1</button>
  </div>
</template>

<script >
import { ref, watchEffect } from 'vue';

export default{
  setup() {
    const counter = ref(100)

    const addCounter = () => counter.value++

    watchEffect(() => {
      console.log("counter:", counter.value);
    })

    return {
      counter,
      addCounter
    }
  }
}

</script>

watchEffect会默认执行一次,当有变量发生变化,就会执行侦听

6.2、watchEffect的其他参数

watchEffect会返回一个返回值,该返回值是一个函数,在满足条件的时候触发返回值函数。我们可以利用这个返回值做一些操作

6.2.1、stop停止侦听

这里我们想要实现计数器增加到15的时候停止侦听:

<template>
  <div>
    <h2>{{ counter }}</h2>
    <button @click="addCounter"> +1 </button>
  </div>
</template>

<script >
import { ref, watchEffect } from 'vue';

export default{
  setup() {
    const counter = ref(10);

    const addCounter = () => {
      counter.value++;
      if(counter.value >= 15){
          stop();
      }
    };

    const stop = watchEffect(() => {
      console.log("counter:", counter.value);
    });

    return {
      counter,
      addCounter
    };
  }
}

</script>

在这里插入图片描述

stop()接收watchEffect的返回值,在手动触发计数器到15之后不再侦听变量的改变。

6.2.2、onInvalidate消除副作用

我们做一个假设,假设我们需要根据counter的值去触发对应的网络请求,但是在请求数据的过程中,我们再次触发方法改变了counter的值,我们该如何做才能让每次请求回来的都是正确的数据呢?

我们也可以这么想,也就是我们只要改变了counter的值,就需要清除上一次的请求,重新执行一次请求。

watchEffect中有一个参数onInvalidate 可以作为消除副作用,它会返回一个函数

<template>
  <div>
    <h2>{{ counter }}</h2>
    <button @click="addCounter">+1</button>
  </div>
</template>

<script >
import { ref, watchEffect } from 'vue';

export default{
  setup() {
    const counter = ref(10)

    const addCounter = () => {
      counter.value++
    }

    watchEffect( onInvalidate => {
      onInvalidate(() => {
        console.log("onInvalidate");
      })
      console.log("counter:", counter.value);
    })

    return {
      counter,
      addCounter
    }
  }
}

</script>

在这里插入图片描述

7、组合式API - 父子通信

7.1、父传子

如果是setup函数的形式,props 必须以 props 选项的方式声明,props 对象会作为 setup() 函数的第一个参数被传入

  • 在vue3中,只要props这个参数存在,我们就可以直接mustache中使用父组件传递的参数

基本思想

  1. 父组件中给子组件绑定属性
  2. 子组件内部通过props选项接收数据

父组件App.vue

<script setup>
// 引入子组件
import sonComVue from './son-com.vue';
</script>

<template>
  <!--1.绑定属性 message-->
  <sonComVue message="this is app message" />
</template>

子组件son-com.vue

<script setup>
  // 2.通过 defineProps 接收子组件传递的数据
  const props = defineProps({
    message: String
  })

</script>

<template>
  <!--使用mustache语法直接使用父组件传递的参数-->  
  {{message}}
</template>

在使用 <script setup> 的单文件组件中,props 可以使用 defineProps() 宏来声明

在这里插入图片描述

7.2、子传父

基本思想

  1. 父组件中给子组件标签通过@绑定事件
  2. 子组件内部通过 emit 方法触发事件

父组件App.vue

<script setup>
// 引入子组件
import sonComVue from './son-com.vue';
const getMessage = (msg) => {
  console.log(msg);
}
</script>

<template>
  <!--1.绑定自定义事件-->
  <sonComVue @get-message="getMessage" />
</template>

子组件son-com.vue

<script setup>
// 2.通过 defineEmits 生成 emit 方法
const emit = defineEmits(['get-message']);

const sendMsg = () => {
  // 3.触发自定义事件,并传递参数
  emit('get-message','this is son msg');
}

</script>

<template>
  <button @click="sendMsg">sendMsg</button>
</template>

在这里插入图片描述

8、组合式API - 模版引用

概念:通过 ref标识 获取真实的 dom对象或者组件实例对象

8.1、获取真实dom对象

实现步骤:

  1. 调用ref函数生成一个ref对象
  2. 通过ref标识绑定ref对象到标签
<script setup>
import  {ref} from 'vue'

// 1.调用 ref 函数得到 ref 对象
const h1Ref = ref(null);
</script>

<template>
  <!-- 2.通过ref标识绑定 ref 对象 -->
  <h1 ref="hrRef">我是dom标签1</h1>
</template>

可以直接拿到真实dom:<h1>我是dom标签1</h1>

注意:

  • 标签中ref的值要和变量名一致
  • 使用ref函数声明数据时,参数是null

8.2、defineExpose

默认情况下在 <script setup>语法糖下组件内部的属性和方法是不开放给父组件访问的,可以通过defineExpose编译宏指定哪些属性和方法容许访问

  • 说明:指定testMessage属性可以被访问到

原代码:

<script setup>
import  {ref} from 'vue'

const testMessage = ref('this is test msg');
</script>

改进:

<script setup>
import  {ref} from 'vue'

const testMessage = ref('this is test msg');
defineExpose({
    testMessage
})
</script>

9、组合式API - provide和inject

  • 通常,当我们需要将数据从父组件传递到子组件时,我们使用 props

  • 想象一下这样的结构:你有一些深嵌套的组件,而你只需要来自深嵌套子组件中父组件的某些内容。在这种情况下,你仍然需要将 prop 传递到整个组件链中,这可能会很烦人。

  • 对于这种情况,我们可以使用 provideinject 对。

  • 顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信

    • 父组件有一个 provide 选项来提供数据,子组件有一个 inject 选项来开始使用这个数据。

9.1、provide

provide() 接受两个参数

  • 第一个参数是要注入的 key,可以是一个字符串或者一个 symbol
  • 第二个参数是要注入的值

9.2、inject

inject 有两个参数:

  • 第一个参数是接收注入的 key
  • 第二个参数是可选的,即在没有匹配到 key 时使用的默认值

9.3、跨层传递数据

实现步骤

  1. 顶层组件通过 provide 函数提供数据
  2. 底层组件通过 inject 函数接收数据

父组件:

<script setup lang="ts">
import { ref, provide } from 'vue'
import ChildComponent from '@/views/articles/ChildComponent.vue'

// 提供响应式的值    
const count = ref(0)
provide('count', count)
    
// 提供静态值    
provide('num', 1)
    
</script>

<template>
  <ChildComponent></ChildComponent>
</template>

子组件:

<script setup lang="ts">
import { inject } from 'vue'
    
// 注入响应式的值
const count = inject('count')

// 注入普通值
const num = inject('num')

// 注入不含默认值的静态值
const other = inject('other')

// 注入一个值,若为空则使用提供的默认值
const otherDefault = inject('otherDefault', 'default')

    
</script>

<template>
  <div>count:{{ count }}</div>
  <div>num:{{ num }}</div>
  <div>other:{{ other }}</div>
  <div>otherDefault:{{ otherDefault }}</div>
</template>

9.4、跨层传递方法

  • 顶层组件可以向底层组件传递方法,底层组件调用方法修改顶层组件的数据

父组件

const setCount = () => {
    count.value++;
}

provide('setCount-key',setCount);

子组件:

const setCount = inject('setCount-key');

这样会出现一个问题,底层组件会修改顶层组件的数据,这样不好,我们还是希望底层组件只是访问而不能修改,所以可以给提供的值加上readonly只读,然后提供出去:

// 提供响应式的值    
const count = ref(0)
provide('count', readonly(count));

10、Vue3.3 新特性-defineOptions

背景说明:

​ 有 <script setup> 之前,如果要定义 props, emits 可以轻而易举地添加一个与 setup 平级的属性。 但是用了 <script setup> 后,就没法这么干了 setup 属性已经没有了,自然无法添加与其平级的属性。

​ 为了解决这一问题,引入了 definePropsdefineEmits 这两个宏。但这只解决了 props 与 emits 这两个属性。如果我们要定义组件的 name 或其他自定义的属性,还是得回到最原始的用法——再添加一个普通的 <script> 标签。这样就会存在两个 <script> 标签。让人无法接受。

​ 所以在 Vue 3.3 中s新引入了 defineOptions 宏。顾名思义,主要是用来定义 Options API 的选项。可以用 defineOptions 定义任意的选项, props, emits, expose, slots 除外(因为这些可以使用 defineXXX 来做到)

<script setup>
defineOptions({
  name: 'Foo',
  inheritAttrs: false,
  // ... 更多自定义属性
})
</script>

11、Vue3.3新特性-defineModel

<script setup>
const modelValue = defineModel()
modelValue.value++
</script>

生效需要配置 vite.config.js

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue({
      script: {
        defineModel: true
      }
    }),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

12、高阶API - mixin

混入 (mixins)定义了一部分可复用的方法或者计算属性。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。

示例:

// 定义混入对象
const myMixin = {
created() {
 this.hello()
},
methods: {
 hello() {
   console.log('欢迎来到混入实例-RUNOOB!')
 }
}
}

// 定义一个应用,使用混入
const app = Vue.createApp({
mixins: [myMixin]
})

app.mount('#app') // => "欢迎来到混入实例-RUNOOB!"
  • 组件的公共逻辑或者配置提取出来,哪个组件需要用到时,直接将提取的这部分混入到组件内部即可。这样既可以减少代码冗余度,也可以让后期维护起来更加容易。
  • 如下代码:我们可以定义一个 mixin 混入对象,将 data 和 methods 进行复用
<div id="app"></div>

<script src="../js/vue.js"></script>
<script>
    // 定义一个mixin混入对象
    const myMixin = {
        data(){
            return {
                message: '你好Vue3!',
            }
        },
        methods: {
            hello() {
                alert('Hello');
            }
        },
    }



    // 1.创建Vue的实例对象
    const app = Vue.createApp({

        // 混入
        mixins: [myMixin],

        template: `
        <div>
          <h1>{{message}}</h1>
          <button @click="hello">打个招呼</button>
    </div>
      `
    });

    app.mount('#app');
</script>
  • 引入 mixin 的方法也非常简单,直接使用 vue 提供的
    mixins 属性

Tips:

  • 实例中的 data、methods之类的选项优先级高于 mixin 中定义的

    • 如果组件自己里面有 data、methods 等属性,但是依然使用了 mixin 属性,此时组件只会用自己的 data、methods 属性
  • 对于生命周期函数,先执行 mixin 中的,再执行实例中的

13、高阶API - 自定义指令

  • 内置指令:v-html、v-if、v-bind、v-on… 这都是Vue给咱们内置的一些指令,可以直接使用
  • 自定义指令:同时Vue也支持让开发者,自己注册一些指令。这些指令被称为自定义指令

自己定义的指令,可以封装一些DOM操作,扩展额外的功能

13.1、自定义指令语法

  • 全局注册
//在main.js中
Vue.directive('指令名', {
  "inserted" (el) {
    // 可以对 el 标签,扩展额外功能
    el.focus()
  }
})
  • 局部注册
//在Vue组件的配置项中
directives: {
  "指令名": {
    inserted () {
      // 可以对 el 标签,扩展额外功能
      el.focus()
    }
  }
}

13.1.1、自定义指令配置项

Vue2的配置项介绍:

  • bind : 指令绑定到元素后调用的钩子。只发生一次

  • inserted:元素插入父DOM后调用的钩子

  • update :当元素更新,但子元素尚未更新时,将调用此钩子

  • componentUpdated:一旦组件和子级被更新,就会调用这个钩子

  • unbind:一旦指令被移除,就会调用这个钩子。也只调用一次。


Vue3的配置项介绍:

  • created :在元素的 attribute 或事件侦听器应用之前调用
  • beforeMount :指令绑定到元素后调用的钩子。只发生一次
  • mounted : 元素插入父DOM后调用的钩子
  • beforeUpdate :在元素本身更新之前调用
  • updated :一旦组件和子级被更新,就会调用这个钩子
  • beforeUnmount :将在卸载元素之前调用
  • unmounted :一旦指令被移除,就会调用这个钩子。也只调用一次。

最终的API如下:

const myDirective = {
  // 在绑定元素的 attribute 前
  // 或事件监听器应用前调用
  created(el, binding, vnode, prevVnode) {
    // 下面会介绍各个参数的细节
  },
  // 在元素被插入到 DOM 前调用
  beforeMount(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都挂载完成后调用
  mounted(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件更新前调用
  beforeUpdate(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都更新后调用
  updated(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载前调用
  beforeUnmount(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载后调用
  unmounted(el, binding, vnode, prevVnode) {}
}

参数如下:

  • el:指令绑定到的元素。这可以用于直接操作 DOM
  • binding:一个对象,包含以下属性
    • value:传递给指令的值。例如在 v-my-directive="1 + 1" 中,值是 2
    • oldValue:之前的值,仅在 beforeUpdateupdated 中可用。无论值是否更改,它都可用
    • arg:传递给指令的参数 (如果有的话)。例如在 v-my-directive:foo 中,参数是 "foo"
    • modifiers:一个包含修饰符的对象 (如果有的话)。例如在 v-my-directive.foo.bar 中,修饰符对象是 { foo: true, bar: true }
    • instance:使用该指令的组件实例。
    • dir:指令的定义对象
  • vnode:代表绑定元素的底层 VNode
  • prevNode:代表之前的渲染中指令所绑定元素的 VNode。仅在 beforeUpdateupdated 钩子中可用。

13.1.2、使用自定义指令

使用指令:例如我们想进入网页输入框自动聚焦

  • 在使用指令的时候,一定要先注册再使用,否则会报错
  • 使用指令语法: v-指令名。如:<input type="text" v-focus/>
  • 注册指令时不用v-前缀,但使用时一定要加v-前缀

自定义全局指令(用的比较多):

<script>
     // 1.创建Vue的实例对象
     const app = Vue.createApp({
      data(){
        return {
          message: '你好Vue3!',
        }
      },
      template:`
        <!--使用自定义指令 v-focus-->
        <input placeholder="请输入姓名" v-focus>
      `
     });

     // 自定义全局指令
     // 第一个参数是指令的名字,第二个参数是指令的操作
     app.directive('focus',{
       // el:把 focus 指令作用到哪个元素上
       mounted(el) {
         el.focus();
       }
     })

     app.mount('#app');
  </script>

自定义局部指令:

<script>

  // 自定义局部指令
  const myDirective = {
    focus: {
      mounted(el){
        el.focus();
      }
    }
  }
  // 1.创建Vue的实例对象
  const app = Vue.createApp({
    data(){
      return {
        message: '你好Vue3!',
      }
    },
    // 挂载局部指令
    directives: myDirective,

    template:`
        <!--使用自定义指令 v-focus-->
        <input placeholder="请输入姓名" v-focus>
      `
  });

  app.mount('#app');
</script>

13.1.3、自定义指令配置项使用

<script>
    // 自定义局部指令
    const myDirective = {
      focus: {
        created(){
          console.log("created()");
        },
        beforeMount(){
          console.log("beforeMount()");
        },
        mounted(el){
          el.focus();
          console.log("mounted()");
        },
        beforeUpdate(){
          console.log("beforeUpdate()");
        },
        updated(){
          console.log("updated()");
        },
        beforeUnmount(){
          console.log("beforeUnmount()");
        },
        unmounted(){
          console.log("unmounted()");
        },
      }
    };

     // 1.创建Vue的实例对象
     const app = Vue.createApp({
      data(){
        return {
          isShow: true,
        }
      },
       // 挂载局部指令
       directives: myDirective,
       template: `
        <div v-show="isShow">
          <input type="text" v-focus>
        </div>
       `
     });

     app.mount('#app');
  </script>

13.1.4、自定义指令__指令的值

  1. 绑定指令时,可以通过“等号”的形式为指令 绑定 具体的参数值
<div v-color="color">我是内容</div>
  1. 通过 binding.value 可以拿到指令值,指令值修改会 触发 update 函数
directives: {
  color: {
    inserted (el, binding) {
      el.style.color = binding.value
    },
    update (el, binding) {
      el.style.color = binding.value
    }
  }
}

14、高阶API - teleport传送门

<Teleport> 是一个内置组件,它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。

  • 假如我们现在有个 button,点击后会将一个蒙版盖在 class='box'div 盒子上
<script>
    // 1.创建Vue的实例对象
    const app = Vue.createApp({
        data(){
            return {
                message: '你好Vue3!',
                isShow: false,
            }
        },
        methods: {
            btnClick(){
                this.isShow = !this.isShow;
            }
        },
        template: `
          <div class="box">
            <button @click="btnClick">蒙版</button>
            <div class="mask" v-show="isShow">{{message}}</div>
       `
    });

app.mount('#app');
</script>

在这里插入图片描述

  • 假如我们想点击 button后会将一个蒙版盖在 body 上,使用 teleport 标签
<script>
    // 1.创建Vue的实例对象
    const app = Vue.createApp({
        data(){
            return {
                message: '你好Vue3!',
                isShow: false,
            }
        },
        methods: {
            btnClick(){
                this.isShow = !this.isShow;
            }
        },
        template: `
          <div class="box">
            <button @click="btnClick">蒙版</button>
            <!--<div class="mask" v-show="isShow">{{message}}</div>-->
            
            <!-- 将蒙版效果传送给 body-->
            <teleport to="body">
              <div class="mask" v-show="isShow">{{message}}</div>
            </teleport>
          </div>
       `
    });

app.mount('#app');
</script>

在这里插入图片描述

如果想传送到其他元素

<!-- 将蒙版效果传送给 id 为 box 的元素 -->
<teleport to="#box">
    <div class="mask" v-show="isShow">{{message}}</div>
</teleport>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1142909.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年中国背光显示面板分类、市场规模及企业分析[图]

背光显示面板行业&#xff0c;指生产背光显示面板及其相关配件的制造商和供应商&#xff0c;这些制造商和供应商主要为电视机、电脑显示器、智能手机等电子产品提供背光显示面板及配件。背光显示面板是一种电子器件&#xff0c;其功能主要是将电信号转化为视觉图像&#xff0c;…

2023年中国调音台产业链、产量及市场规模分析[图]

调音台是一种专业音频设备&#xff0c;用于混音、处理和控制音频信号。它通常用于音乐制作、现场演出、录音室以及广播等场景中。调音台允许用户调整不同声音来源的音频信号&#xff0c;使其在混音过程中达到理想的音质和平衡。调音台按信号出来方式可分为&#xff1a;模拟式调…

业务设计——注册用户如何防止缓存穿透

什么是缓存穿透 缓存穿透是指在使用缓存系统时&#xff0c;恶意或频繁地请求一个不存在于缓存中的数据&#xff0c;导致每次请求都需要查询数据库或其他数据存储系统&#xff0c;从而绕过了缓存的效果&#xff0c;严重影响系统性能。 这种情况通常发生在恶意攻击、大量请求缓存…

高可用集群 keepalived

一、高可用集群&#xff1a; 1、简介&#xff1a; 高可用集群&#xff08;High Availability Cluster&#xff0c;简称 HA Cluster&#xff09;&#xff0c;是一组相互连接的计算机或服务器&#xff0c;它通过保护用户的业务程序对外不间断提供的服务&#xff0c;把因软件、硬…

PHP如何批量修改二维数组中值

每个name值加pex&#xff0c;age加5&#xff0c; 原数据&#xff1a; $data[["name">a,age>12],["name">b,age>22],["name">c,age>33],["name">d,age>44], ];实现效果 方案一、foreach引用方式 $data[["…

7 款好用的 PDF 密码删除工具

这是最佳 PDF 密码删除工具列表。该列表包括免费和付费软件。将要在线完成的所有事情都需要密码才能感到安全。数据传输也是如此。大多数数据是通过文件传输的&#xff0c;PDF有自己的标志。PDF是一种灵活的文件格式&#xff0c;因此也可以专业使用。 有多种PDF 编辑器软件&am…

echart 设置 legend.type=“scroll“ 翻页时,中文上面被截取,显示不完整,解决办法

问题如图&#xff1a; 修复后的样子&#xff1a; 设置 legend 的 padding height 和 grid 都没有效果&#xff0c;最终找到办法&#xff1a; legend: {itemHeight: 10, // 截取原因是这里设置的太小textStyle: {fontSize: 20,// 行高设置会改变文本区域的高度&#xff0c;不…

SpringMVC Day 04 : 数据绑定

前言 SpringMVC是一个非常流行的Java Web框架&#xff0c;它提供了很多方便的功能和工具来帮助我们构建高效、灵活的Web应用程序。其中&#xff0c;数据绑定就是SpringMVC中非常重要的一部分&#xff0c;它可以帮助我们方便地将请求参数绑定到Java对象上&#xff0c;从而简化了…

北美干旱监测 (NADM)数据集

北美干旱监测 (NADM) 栅格数据集由国家环境信息中心 (NCEI) 和国家海洋和大气管理局 (NOAA) 国家综合干旱信息系统 (NIDIS) 生成。该数据集是加拿大、墨西哥和美国作者制作的北美干旱监测 (NADM) 的网格版本&#xff0c;其中对于每个 2.5 公里网格单元&#xff0c;该值由该地区…

hdlbits系列verilog解答(32位加法器)-25

文章目录 一、问题描述二、verilog源码三、仿真结果 一、问题描述 您将获得一个执行 16 位加法的模块 add16 。实例化其中两个以创建一个 32 位加法器。一个 add16 模块在接收到第一个加法器的进位结果后&#xff0c;计算加法结果的低 16 位&#xff0c;而第二个 add16 模块计…

大厂面试题-什么是JVM

JVM全称是Java虚拟机&#xff0c;在聊什么是JVM之前&#xff0c;我们不妨看⼀下这张图。 从这张图中可以看出JVM所处的位置&#xff0c;同时也能看出它两个作用&#xff1a; 1、运⾏并管理Java源码⽂件所⽣成的Class⽂件&#xff0c; 2、在不同的操作系统上安装不同的JVM&#…

搭建微信小程序环境及项目结构介绍

一、注册 访问微信公众平台&#xff0c;将鼠标的光标置于账号分类中的小程序上&#xff0c; 点击‘查看详情’ 点击“前往注册” 下方也可以点击注册&#xff1a; 小程序注册页面&#xff1a; 步骤a:进入小程序注册页&#xff0c;根据指引填写信息和提交相应的资料&#x…

VR步进式漫游,轻松构建三维模型,带来展示新形式!

引言&#xff1a; 虚拟现实&#xff08;Virtual Reality&#xff0c;简称VR&#xff09;已经成为当今科技领域的一项创新力量&#xff0c;它正在逐渐渗透到不同的领域&#xff0c;其中步进式漫游是VR技术的一项重要应用&#xff0c;它能在各个行业的宣传中发挥重要作用。 一&a…

20.1 OpenSSL 字符BASE64压缩算法

OpenSSL 是一种开源的加密库&#xff0c;提供了一组用于加密和解密数据、验证数字证书以及实现各种安全协议的函数和工具。它可以用于创建和管理公钥和私钥、数字证书和其他安全凭据&#xff0c;还支持SSL/TLS、SSH、S/MIME、PKCS等常见的加密协议和标准。 OpenSSL 的功能非常…

驱动作业10.28

驱动程序 #include <linux/init.h> #include <linux/module.h> #include<linux/of.h> #include<linux/of_gpio.h> #include<linux/gpio.h> #include<linux/timer.h> #include <linux/fs.h> #include <linux/io.h> #include &…

SpringCloud复习:(7)@EnableZuulProxy注解的作用

使用zuul时&#xff0c;需要加EnableZuulProxy注解&#xff0c;这个注解定义如下&#xff1a; 可以看到&#xff0c;它引入了一个配置类ZuulProxyMarkerConfiguration,这个类代码如下&#xff1a; 其中定义了一个类型为ZuulProxyMarkerConfiguration.Marker类型的bean. 这个…

QPushButton样式设置

QPushButton样式设置 Chapter1 QPushButton样式设置无样式的按钮改变字体颜色改变字体改变字号改变背景颜色设置上边框为2个像素&#xff0c;样式为实线&#xff0c;颜色为黑色设置所有边框为2个像素&#xff0c;样式为实线&#xff0c;颜色为黑色设置左上角圆角为&#xff1a;…

使用一个Series序列减去另一个Series序列Series.subtract()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 求两个序列中对应位置 的各元素的差 a.subtract(b) [太阳]选择题 关于以下代码的说法中正确的是? import pandas as pd a pd.Series([1,2,3]) print("【显示】a:\n",a) b pd.Seri…

服务运营 |文章精选:运筹学视角下的众包竞赛

作者&#xff1a; Guo 编者按&#xff1a;众包竞赛&#xff08;Crowdsourcing Contests&#xff09;是一种利用大规模在线社群或平台来解决问题、完成任务或创新的方法。众包竞赛通常在在线平台上进行&#xff0c;这些平台提供任务发布、参与者注册、提交作品、评审等功能。一…

向量数据库Weaviate Cloud 和 Milvus Cloud:性能大比拼

最近,随着检索增强生成系统(RAG)的持续火爆,开发者对于“如何选择一个向量数据库”的疑惑也越来越多。过去几周,我们从性能和特性能力两个方面对 Weaviate Cloud 和 MilvusCloud 进行了详细的对比。在对比过程中,我们使用了开源的性能基准测试套件 VectorDBBench,围绕诸…