【Vue3重点概念总结和实践八】(自定义切换焦点指令v-focus / 自定义防抖指令v-debounce-click:ms / 自定义节流指令 v-throttle-click:ms / 函数式组)

目录

1、自定义切换焦点指令v-focus

2、自定义防抖指令 v-debounce-click:ms

3、自定义节流指令 v-throttle-click:ms

4、函数式组件

5、Vue3 + Vue-cli (1) 基础篇

6、Vue3+ Vue-cli (2) 组件篇


1、自定义切换焦点指令v-focus

原题: 

自定义指令:当一个 input 元素被 Vue 插入到 DOM 中后,它会被自动聚焦。

https://github.com/webfansplz/vuejs-challenges/blob/main/questions/19-v-focus/README.zh-CN.md

答案:

一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。

<script setup>
import { ref } from 'vue'
const state = ref(false)

/**
 * 实现一个自定义指令,让元素获取焦点
 * 确保当切换`state`时,元素随着状态值获取/失去焦点
 */
const VFocus = {
  // 在绑定元素的 attribute 前
  // 或事件监听器应用前调用
  created(el, binding, vnode, prevVnode) {
    console.log(el, binding, vnode, prevVnode)
  },

  // 在元素被插入到 DOM 前调用
  beforeMount(el, binding, vnode, prevVnode) {
    console.log('beforeMount')
  },

  // 在绑定元素的父组件
  // 及他自己的所有子节点都挂载完成后调用
  mounted(el, binding, vnode, prevVnode) {
    console.log('mounted')
  },

  // 绑定元素的父组件更新前调用
  beforeUpdate(el, binding, vnode, prevVnode) {
    console.log('beforeUpdate')
  },

  // 在绑定元素的父组件
  // 及他自己的所有子节点都更新后调用
  updated(el, { value }) {
    console.log('updated', value)
    value ? el.focus() : el.blur()
  },

  // 绑定元素的父组件卸载前调用
  beforeUnmount(el, binding, vnode, prevVnode) {
    console.log('beforeUnmount')
  },

  // 绑定元素的父组件卸载后调用
  unmounted(el, binding, vnode, prevVnode) {
    console.log('unmounted')
  }
}

// Vue3.x不需要这段声明
// const app = createApp({})
// app.directive('focus', VFocus)

setInterval(() => {
  state.value = !state.value
}, 2000)
</script>

<template>
  <input v-focus="state" type="text" />
</template>

文档:

自定义指令 | Vue.js

2、自定义防抖指令 v-debounce-click:ms

原题: 

自定义指令:确保在一定时间内当快速点击按钮多次时只触发一次点击事件。
你需要支持防抖延迟时间选项, 用法如 `v-debounce-click:ms`

https://github.com/webfansplz/vuejs-challenges/blob/main/questions/20-v-debounce-click/README.zh-CN.md

答案:

函数防抖,在一段连续操作结束后,处理回调,利用clearTimeout 和 setTimeout实现。

函数防抖关注一定时间连续触发的事件只在最后执行一次。

<script setup>
const VDebounceClick = {
  mounted(el, { value, arg }) {
    const debounce = (fn, delay, ...args) => {
      let timer = 0
      return () => {
        if (timer) {
          clearTimeout(timer)
        }
        timer = setTimeout(() => {
          fn.apply(this, ...args)
        }, delay)
      }
    }
    el.addEventListener('click', debounce(value, Number(arg)))
  }
}

function onClick() {
  console.log('Only triggered once when clicked many times quicky')
}

</script>

<template>
  <button v-debounce-click:500="onClick">Click on it many times quickly</button>
</template>

3、自定义节流指令 v-throttle-click:ms

原题:

函数节流,在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能。
函数节流侧重于一段时间内只执行一次。

答案:

<script setup>
const VThrottleClick = {
  mounted(el, { value, arg }) {
    const throttle = (fn, delay, ...args) => {
      let timer = 0
      return () => {
        if (timer) {
          return
        }

        timer = setTimeout(() => {
          fn.apply(this, ...args)
          timer = 0
        }, delay)
      }
    }
    el.addEventListener('click', throttle(value, Number(arg)))
  }
}

function onClick() {
  console.log('Only triggered once when clicked many times quicky')
}
</script>

<template>
  <button v-throttle-click:2000="onClick">Click on it many times quickly</button>
</template>

4、函数式组件

原题: 

vuejs-challenges/questions/21-functional-component/README.zh-CN.md at main · webfansplz/vuejs-challenges · GitHub

答案:

函数式组件是一种定义自身没有任何状态的组件的方式。

它们很像纯函数:接收 props,返回 vnodes。函数式组件在渲染过程中不会创建组件实例 (也就是说,没有 this),也不会触发常规的组件生命周期钩子。

我们用一个普通的函数而不是一个选项对象来创建函数式组件。该函数实际上就是该组件的渲染函数。

函数式组件可以像普通组件一样被注册和使用。如果你将一个函数作为第一个参数传入 h,它将会被当作一个函数式组件来对待。 

<script setup>
import { ref, h } from 'vue'
/**
 * 实现该函数式组件 :
 * 1. 使用`list`数据渲染列表元素 (ul/li)
 * 2. 当点击列表子元素时,将其文本颜色更改为红色
 */
const ListComponent = (props, { emit }) => {
  let content = []
  props.list.map((item, index) => {
    content.push(
      h('li', {
        innerText: item.name,
        index,
        style: props['active-index'] === index ? { color: 'red' } : undefined,
        onClick: async () => {
          await emit('toggle', index)
        }
      })
    )
  })
  return h('ul', content)
}

const list = [{name: 'John'}, {name: 'Doe'},{name: 'Smith'}]
const activeIndex = ref(0)
function toggle(index) {
  activeIndex.value = index
}

</script>

<template>
  <list-component :list="list" :active-index="activeIndex" @toggle="toggle" />
</template>

文档:

渲染函数 & JSX | Vue.js

5、Vue3 + Vue-cli (1) 基础篇

Vue3 + Vue-cli (1) 基础篇_vue3 vue-cli_小草莓蹦蹦跳的博客-CSDN博客

6、Vue3+ Vue-cli (2) 组件篇

Vue3+ Vue-cli (2) 组件篇_vue3 text root nodes_小草莓蹦蹦跳的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值