赞
踩
目录
vue3 中的 hooks 就是函数的一种写法,就是将文件的一些单独功能的 js 代码进行抽离出来进行封装使用。
它的主要作用是 Vue3 借鉴了 React 的一种机制,用于在函数组件中共享状态逻辑和副作用,从而实现代码的可复用性。
注意:其实 hooks 和 vue2 中的 mixin 有点类似,但是相对 mixins 而言, hooks 更清楚复用功能代码的来源, 更清晰易懂。
示例如下:
const{ nameRef, Fn } = useXX()
通过 hooks 和 utils 函数封装, 可以实现组件间共享和复用,提高代码的可重用性和可维护性。
utils 是通用的工具函数,而 hooks 是对 utils 的一种封装,用于在组件中共享状态逻辑和副作用。
通过使用 hooks,您可以简化代码,并使其更具可读性和可维护性。
hooks 和 mixin,都是常用代码逻辑抽离手段,方便进行代码复用;
优点:组件中相同代码逻辑复用;
缺点:
注:VUE3 提出的 Composition API 旨在解决这些问题。mixins 的缺点是 Composition API 背后的主要动因之一,Composition API 受到 React Hooks 的启发。
hooks 代码:
useCount.ts 函数示例:
- import{ ref, onMounted, computed } from'vue';
-
- exportdefaultfunctionuseCount{
-
- constcount = ref(0);
-
- constdoubleCount = computed(
- ()=>count.value * 2
- );
-
- constincrease = (delta) =>{
- returncount.value + delta;
- }
-
- return{
- count,
- doubleCount,
- increase
- };
-
- }
useCount 在组件中调用:
- importuseCount from"@/hooks/useCount";
- const{(count, doubleCount, increase)} = useCount;
- constnewCount = increase(10); // 输出: 10
Mixins 的代码:
- exportdefaultconstcountMixin = {
- data() {
- return{
- count: 0
- };
- },
- computed: {
- doubleCount() {
- returnthis.count * 2;
- }
- },
- methods: {
- increase(delta){
- returnthis.count + delta;
- }
- };
Mixins 在组件中调用:
- <scriptsetuplang="ts">
- importcountMixin from'@/mixin/countMixin'
- exportdefault{
- mixins: [countMixin],
- mounted() {
- console.log(this.doubleCount) // 输出: 0
- constnewCount = this.setIncrease(10) // 输出: 10
- },
- methods: {
- setIncrease(count) {
- this.increase(count)
- },
- },
- }
- </script>
这两个示例展示了使用 Hooks 和 Mixins 的代码风格和组织方式的不同。Hooks 使用函数式的方式来定义逻辑和状态,而 Mixins 则是通过对象的方式进行组合和共享代码。
Vue3 自定义 Hooks 是组件下的函数作用域的,而 Vue2 时代的 Mixins 是组件下的全局作用域。全局作用域有时候是不可控的,就像 var 和 let 这些变量声明关键字一样,const 和 let 是 var 的修正。Composition Api 正是对 Vue2 时代 Option Api 高耦合和随处可见 this 的黑盒的修正,Vue3 自定义 Hooks 是一种进步。
useDownload 函数封装:
- import{ ElNotification } from'element-plus'
- /**
- * @description 接收数据流生成 blob,创建链接,下载文件
- * @param {any} data 导出的文件blob数据 (必传)
- * @param {String} tempName 导出的文件名 (必传)
- * @param {Boolean} isNotify 是否有导出消息提示 (默认为 true)
- * @param {String} fileType 导出的文件格式 (默认为.xlsx)
- * */
- interfaceuseDownloadParam {
- data: any;
- tempName: string;
- isNotify?: boolean;
- fileType?: string;
- }
-
- exportconstuseDownload = async({
- data,
- tempName,
- isNotify = true,
- fileType = '.xlsx',
- }: useDownloadParam) => {
- if(isNotify) {
- ElNotification({
- title: '温馨提示',
- message: '如果数据庞大会导致下载缓慢哦,请您耐心等待!',
- type: 'info',
- duration: 3000,
- })
- }
- try{
- constblob = newBlob([data])
- // 兼容 edge 不支持 createObjectURL 方法
- if('msSaveOrOpenBlob'innavigator)
- returnwindow.navigator.msSaveOrOpenBlob(blob, tempName + fileType)
- constblobUrl = window.URL.createObjectURL(blob)
- constexportFile = document.createElement('a')
- exportFile.style.display = 'none'
- exportFile.download = `${tempName}${fileType}`
- exportFile.href = blobUrl
- document.body.appendChild(exportFile)
- exportFile.click()
- // 去除下载对 url 的影响
- document.body.removeChild(exportFile)
- window.URL.revokeObjectURL(blobUrl)
- } catch(error) {
- console.log(error)
- }
- }
useDownload 在组件中使用:
- <scriptsetuplang="ts">
- import{ useDownload } from"@/hooks/useDownload";
-
- constuserForm = reactive({})
- constuserListExport = ()=>{
- newPromise(resolve=>{
- $Request({
- url: $Urls.userListExport,
- method: "post",
- data: userForm,
- responseType: "blob"
- }).then((res: any) =>{
- useDownload({
- data: res.data,
- tempName:"用户列表"
- });
- resolve(res);
- });
- });
- };
- </script>
useCount 函数封装:
- import{ computed, ref, Ref } from'vue'
- // 定义hook方法
- typeCountResultProps = {
- count: Ref<number>,
- multiple: Ref<number>, // 计算属性
- increase: (delta?: number) =>void,
- decrease: (delta?: number) =>void,
- }
-
- exportdefaultfunctionuseCount(initValue = 1): CountResultProps{
- constcount = ref(initValue)
-
- constmultiple = computed(()=>count.value * 2)
-
- constincrease = (delta?: number): void=>{
- if(typeofdelta !== 'undefined') {
- count.value += delta
- } else{
- count.value += 1
- }
- }
-
- constdecrease = (delta?: number): void=>{
- if(typeofdelta !== 'undefined') {
- count.value -= delta
- } else{
- count.value -= 1
- }
- }
- return{
- count,
- increase,
- decrease,
- multiple,
- }
- }
useCount 函数在组件中使用:
- <template>
- <p>count:{{count}}</p>
- <p>倍数:{{multiple}}</p>
- <div>
- <button@click="increase(1)">加一</button>
- <button@click="decrease(1)">减一</button>// 在模版中直接使用hooks中的方法作为回调函数
- </div>
- </template>
-
- <scriptsetuplang="ts">
- importuseCount from"@/hooks/useCount"
- const{count,multiple,increase,decrease} = useCount(10)
- </script>
useMousePosition 函数封装:
- import{ ref, onMounted, onUnmounted, Ref } from'vue'
-
- interfaceMousePosition {
- x: Ref<number>;
- y: Ref<number>;
- }
-
- exportdefaultfunctionuseMousePosition(): MousePosition{
- constx = ref(0)
- consty = ref(0)
-
- constupdateMouse = (e: MouseEvent) =>{
- x.value = e.pageX
- y.value = e.pageY
- }
-
- onMounted(()=>{
- document.addEventListener('click', updateMouse)
- })
-
- onUnmounted(()=>{
- document.removeEventListener('click', updateMouse)
- })
-
- return{ x, y }
- }
useMousePosition 在组件中使用:
- <template>
- <div>
- <p>X: {{ x }}</p>
- <p>Y: {{ y }}</p>
- </div>
- </template>
- <scriptlang="ts">
- importuseMousePosition from'@/hooks/useMousePosition'
- const{ x, y } = useMousePosition();
- </script>
1.hooks 函数接收参数写法;
写法 1:参数通过 props 接收,先定义参数类型,内部再解构;
- exportfunctioncommonRequest(params: Axios.AxiosParams) {
- let{ url, method, data, responseType = 'json'} = params
- }
写法 2:接收传参对象,先设置默认值,再定义参数类型
- interfaceDeprecationParam {
- from: string;
- replacement: string;
- type: string;
- }
- exportconstuseDeprecated = ({ from, replacement, type= 'API' }: DeprecationParam) =>{}
2.解构重命名写法
- // setup中
-
- const { list:goodsList, getList:getGoodsList } = useList(axios.get('/url/get/goods'))
- const { list:recommendList, getList:getRecommendList } = useList(
- axios.get('/url/get/recommendGoods')
- )
3.KeyboardEvent 为鼠标按键类型
exportconstuseEscapeKeydown = (handler: (e: KeyboardEvent) => void) =>{}
Vue2 时代 Option Api ,data、methos、watch.....分开写,这种是碎片化的分散的,代码一多就容易高耦合,维护时来回切换代码是繁琐的!
Vue3 时代 Composition Api,通过利用各种 Hooks 和自定义 Hooks 将碎片化的响应式变量和方法按功能分块写,实现高内聚低耦合。
作者 :吴冬林 |高级前端开发工程师
版权声明:本文由神州数码云基地团队整理撰写,若转载请注明出处。
公众号搜索神州数码云基地,了解更多技术干货。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。