【vue2】vue2中的“组合式函数”?(复用公共逻辑)

前言

在我学习 vue3 之后,觉得相同功能的代码逻辑放在一起的方式确实比 vue2 那种变量按类型分开管理的好使;于是我尝试在 vue2 中找出类似 vue3 组合式函数那种的写法…

开始

我以两个小例子来说明

useMouse

官网例子的改写

这个是vue3的 组合式函数的例子

// mouse.js
import { ref, onMounted, onUnmounted } from 'vue'

// 按照惯例,组合式函数名以“use”开头
export function useMouse() {
  // 被组合式函数封装和管理的状态
  const x = ref(0)
  const y = ref(0)

  // 组合式函数可以随时更改其状态。
  function update(event) {
    x.value = event.pageX
    y.value = event.pageY
  }

  // 一个组合式函数也可以挂靠在所属组件的生命周期上
  // 来启动和卸载副作用
  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))

  // 通过返回值暴露所管理的状态
  return { x, y }
}

而在 vue2 中可以这么实现

原理

  1. 利用 Vue.observable 实现创建响应式数据
  2. 利用 mixins 实现生命周期的添加

具体实现

// hook/useMouse
import Vue from "vue";

export function useMouse() {
  // 被组合式函数封装和管理的状态
  const x = Vue.observable({ value: 0 });
  const y = Vue.observable({ value: 0 });

  // 组合式函数可以随时更改其状态。
  function update(event) {
    x.value = event.pageX;
    y.value = event.pageY;
  }

  // 一个组合式函数也可以挂靠在所属组件的生命周期上
  // 来启动和卸载副作用
  const mixins = {
    mounted() {
      window.addEventListener("mousemove", update);
    },
    destroyed() {
      window.removeEventListener("mousemove", update);
    },
  };
  // 通过返回值暴露所管理的状态
  return { x, y, mixins };
}

页面中使用

<template>
  <div class="example">
    <div>({{ mouseX }}, {{ mouseY }})</div>
  </div>
</template>

<script>
import { useMouse } from "./hook/useMouse";


const { x, y, mixins: mouseMixins } = useMouse();

export default {
  components: {},
  props: {},
  mixins: [mouseMixins],
  data() {
    return {
      mouseX: x,
      mouseY: y,
    };
  },
};
</script>

useScrollList

这个是把每次都要滚动加载的功能进行了一个简单抽离,以方便复用,去应付其他的滚动加载

直接上代码

import Vue from "vue";

function useScrollList(options = {}) {
  const { requestApi, pageParams } = options;
  const list = Vue.observable([]);
  const pageData = Vue.observable({
    page: 1,
    pageSize: 15,
    lastPage: 1,
  });
  if (pageParams) {
    Object.assign(pageData, pageParams);
  }
  let loading = false;
  async function getList(options) {
    try {
      if (pageData.page > pageData.lastPage || loading) return;
      loading = true;
      const res = await requestApi({
        page: pageData.page,
        pageSize: pageData.pageSize,
      });
      list.push(...res.data);
      pageData.lastPage = res.last_page;
      pageData.page += 1;
    } catch (error) {
    } finally {
      loading = false;
    }
  }

  return {
    list,
    getList,
  };
}

export { useScrollList };

页面使用上

<template>
  <div class="example" @scroll="handleScroll">
    <ul>
      <li v-for="game in gameList" :key="game.id">
        <pre>
          {{ game }}
        </pre>
      </li>
    </ul>
  </div>
</template>

<script>
import { getGameApi } from "./api/game";
import { useScrollList } from "./hook/useList";
import { useMouse } from "./hook/useMouse";

const { list: gameList, getList: getGameList } = useScrollList({
  requestApi: getGameApi,
  pageParams: {
    pageSize: 12,
  },
});

export default {
  components: {},
  props: {},
  data() {
    return {
      gameList,
    };
  },
  created() {
    getGameList();
  },
  methods: {
    handleScroll(event) {
      const el = event.target;
      const scrollTop = el.scrollTop;
      const scrollHeight = el.scrollHeight;
      const clientHeight = el.clientHeight;
      if (Math.ceil(scrollTop + clientHeight) >= scrollHeight) {
        getGameList();
      }
    },
  },
};
</script>

<style>
.example {
  height: 100vh;
  overflow: hidden;
  overflow-y: scroll;
}
</style>


最后再看一看

  1. Vue.observable 不能监听基础类型像 number;所以可以使用{value: 其他数据类型},就像vue3那样,但是在页面上是不会解构的,所以使用时别忘记加.value
  2. Vue.observable 返回的变量具有响应式,所以它不应该被修改,比如想清空数组时候 直接list = [] 是不行的,可以用splice或者其他方式,最重要的是不能直接修改原数组!

思考

  1. 这个其实像 vuex 状态管理,但是它不是全局的,是小范围的状态管理;因为我可能只在这个页面及其组件会用到某个数据;
  2. 减少了挺多父子组件之间的传参,比如有些人喜欢在父组件进行删除事件,有些人又在子组件进行删除事件,不统一的时候,会造成比较多的困惑;

源码

https://github.com/adcGG/article-project.git 里面的 vue-function 文件夹

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值