前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >vue3的composition-api实践总结

vue3的composition-api实践总结

作者头像
winty
发布于 2021-07-27 06:50:30
发布于 2021-07-27 06:50:30
88700
代码可运行
举报
文章被收录于专栏:前端Q前端Q
运行总次数:0
代码可运行

因为向往已久vue3的开发方式,但是组内有很多历史项目,并且我们受制于ie的支持,所以我们决定在vue2中引入composition-api,来使用他的新特性。在使用过程中,我们遇到了很多问题,也积累了一些经验,所以记录下。

composition-api

首先给大家介绍一下composition-api,他是通过函数的形式,将vue的功能特性暴露给我们使用

虽然一下子看上去很多,但是只需要先掌握加粗的这一部分,就可以体验到组合式api的魅力了,其他的可以先做了解等到你真的需要使用它们的时候在做深入。

reactive 用来将对象转变为响应式的,与vue2的observable类似,ref用来获得单独或者为基础数据类型获得响应性。为什会会有两个获得响应性的api呢稍后我们将具体说明。computed、watch,provide、inject不用怀疑和vue2中做的是一样的事情。

你一定注意到下面这些加了on开头的生命周期钩子函数,没错在组合式api中,这就是他们注册的方式。但是为什么不见了beforeCreate和created呢?因为setup就是在这个阶段执行的,而setup就是打开组合式api世界的大门。你可以把setup理解为class的constructor,在vue组件的创建阶段,把我们的相关逻辑执行,并且注册相关的副作用函数。

现在我们说回ref和reactive。

  • reactive在官网中的说明,接受一个对象,返回对象的响应式副本。ref在官网中的描述"接受一个内部值并返回一个响应式且可变的 ref 对象。
  • ref 对象具有指向内部值的单个 property.value"。

听着很绕口,简单来讲就是reactive可以为对象创建响应式而ref除了对象,还可以接收基础数据类型,比如string、boolean等。 那为什么会有这种差异呢?在vue3当中响应式是基于proxy实现的,而proxy的target必须是复杂数据类型,也就是存放在堆内存中,通过指针引用的对象。其实也很好理解,因为基础数据类型,每一次赋值都是全新的对象,所以根本无法代理。那么如果我们想取得简单类型的响应式怎么办呢?这时候就需要用到ref。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class RefImpl<T> {
  private _value: T

  public readonly __v_isRef = true

  constructor(private _rawValue: T, public readonly _shallow = false) {
    this._value = _shallow ? _rawValue : convert(_rawValue)
  }

  get value() {
    track(toRaw(this), TrackOpTypes.GET, 'value')
    return this._value
  }

  set value(newVal) {
    if (hasChanged(toRaw(newVal), this._rawValue)) {
      this._rawValue = newVal
      this._value = this._shallow ? newVal : convert(newVal)
      trigger(toRaw(this), TriggerOpTypes.SET, 'value', newVal)
    }
  }
}
...
const convert = <T extends unknown>(val: T): T =>
  isObject(val) ? reactive(val) : val
...

ref通过创建内部状态,将值挂在value上,所以ref生成的对象,要通过value使用。重写get/set获得的监听,同时对对象的处理,也依赖了reactive的实现。

由此,ref并不只是具有对基本数据类型的响应式处理能力,他也是可以处理对象的。所以我认为ref和reactive的区分并不应该只是简单/复杂对象的区分,而是应该用编程思想区分的。我们应该避免,把reactive 当作data在顶部将所有变量声明的想法,而是应该结合具体的逻辑功能,比如一个控制灰度的Flag那他就应该是一个ref,而分页当中的页码,pageSize,total等就应该是一个reactive声明的对象。也就是说一个setup当中可以有多出响应变量的声明,而且他们应当是与逻辑紧密结合的.

接下来我先用一个分页的功能,用选项式和组合式api给大家对比一下。

一些例子

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<template>
    <div>
        <ul class="article-list">
            <li v-for="item in articleList" :key="item.id">
                <div>
                    <div class="title">{{ item.title }}</div>
                    <div class="content">{{ item.content }}</div>
                </div>
            </li>
        </ul>
        <el-pagination
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
            :current-page="currentPage"
            :page-sizes="pageSizes"
            :page-size="pageSize"
            layout="total, sizes, prev, pager, next, jumper"
            :total="total"
        >
        </el-pagination>
    </div>
</template>

<script>
import { getArticleList } from '@/mock/index';
export default {
    data() {
        return {
            articleList: [],
            currentPage: 1,
            pageSizes: [5, 10, 20],
            pageSize: 5,
            total: 0,
        };
    },
    created() {
        this.getList();
    },
    methods: {
        getList() {
            const param = {
                currentPage: this.currentPage,
                pageSizes: this.pageSizes,
                pageSize: this.pageSize,
            };
            getArticleList(param).then((res) => {
                this.articleList = res.data;
                this.total = res.total;
            });
        },
        handleSizeChange(val) {
            this.pageSize = val;
            this.getList();
        },
        handleCurrentChange(val) {
            this.currentPage = val;
            this.getList();
        },
    },
};
</script>

这还是我们熟悉到不能在熟悉的分页流程,在data中声明数据,在method中提供修分页的方法。当我们用composition-api实现的时候他就成了下面的样子。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<script>
import { defineComponent, reactive, ref, toRefs } from "@vue/composition-api";
import { getArticleList } from "@/mock/index";
export default defineComponent({
  setup() {
    const page = reactive({
      currentPage: 1,
      pageSizes: [5, 10, 20],
      pageSize: 5,
      total: 0,
    });
    function handleSizeChange(val) {
      page.pageSize = val;
      getList();
    }
    function handleCurrentChange(val) {
      page.currentPage = val;
      getList();
    }

    const articleList = ref([]);
    function getList() {
      getArticleList(page).then((res) => {
        articleList.value = res.data;
        page.total = res.total;
      });
    }
    getList();
    return {
      ...toRefs(page),
      articleList,
      getList,
      handleSizeChange,
      handleCurrentChange,
    };
  },
});
</script>

这是以composition-api的方式实现的分页,你会发现原本的data,method,还有声明周期等选项都不见了,所有的逻辑都放到了setup当中。通过这一个简单的例子,我们可以发现原本分散在各个选项中的逻辑,在这里得到了聚合。这种变化在复杂场景下更为明显。在复杂组件中,这种情况更加明显。而且当逻辑完全聚集在一起,这时候,将他们抽离出来,而且抽离逻辑的可以在别处复用,至此hook就形成了。

hook形态的分页组件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// hooks/useArticleList.js
import { ref } from "@vue/composition-api";
import { getArticleList } from "@/mock/index"; // mock ajax请求

function useArticleList() {
  const articleList = ref([]);
  function getList(page) {
    getArticleList(page).then((res) => {
      articleList.value = res.data;
      page.total = res.total;
    });
  }
  return {
    articleList,
    getList,
  };
}
export default useArticleList;

// hooks/usePage.js
import { reactive } from "@vue/composition-api";

function usePage(changeFn) {
  const page = reactive({
    currentPage: 1,
    pageSizes: [5, 10, 20],
    pageSize: 5,
    total: 0,
  });
  function handleSizeChange(val) {
    page.pageSize = val;
    changeFn(page);
  }
  function handleCurrentChange(val) {
    page.currentPage = val;
    changeFn(page);
  }
  return {
    page,
    handleSizeChange,
    handleCurrentChange,
  };
}
export default usePage;

// views/List.vue
import { defineComponent, toRefs } from "@vue/composition-api";
import usePage from "@/hooks/usePage";
import useArticleList from "@/hooks/useArticleList";
export default defineComponent({
  setup() {
    const { articleList, getList } = useArticleList();
    const { page, handleSizeChange, handleCurrentChange } = usePage(getList);
    getList(page);
    return {
      ...toRefs(page),
      articleList,
      getList,
      handleSizeChange,
      handleCurrentChange,
    };
  },
});

在hook使用过程中我们也踩过很多坑

  1. hook中的异步问题 因为hook本质上就是函数,所以灵活度非常高,尤其是在涉及异步的逻辑中,考虑不全面就很有可能造成很多问题。hook是可以覆盖异步情况的,但是必须在setup当中执行时返回有效对象不能被阻塞。

我们总结了两种异步的风格,通过一个简单的hook为例

  • 外部没有其他依赖,只是交付渲染的响应变量 对于这种情况,可以通过声明、对外暴露响应变量,在hook中异步修改的方式
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// hooks/useWarehouse.js
import { reactive,toRefs } from '@vue/composition-api';
import { queryWarehouse } from '@/mock/index';  // 查询仓库的请求
import getParam from '@/utils/getParam'; // 获得一些参数的方法
function useWarehouse(admin) {
    const warehouse = reactive({ warehouseList: [] });
    const param = { id: admin.id, ...getParam() };
    const queryList = async () => {
        const { list } = await queryWarehouse(param);
        list.forEach(goods=>{
        // 一些逻辑...
          return goods
        })
        warehouse.warehouseList = list;
    };
    return { ...toRefs(warehouse), queryList };
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export default useWarehouse;// components/Warehouse.vue
<template>
    <div>
        <button @click="queryList">queryList</button>
        <ul>
            <li v-for="goods in warehouseList" :key="goods.id">
                {{goods}}
            </li>
        </ul>
    </div>
</template>

<script>
import { defineComponent } from '@vue/composition-api';
import useWarehouse from '@/hooks/useWarehouse';
export default defineComponent({
    setup() {
        // 仓库保管员
        const admin = {
            id: '1234',
            name: '张三',
            age: 28,
            sex: 'men',
        };
        const { warehouseList, queryList } = useWarehouse(admin);
        return { warehouseList, queryList };
    },
});
</script>
  • 外部具有依赖,需要在使用侧进行加工的 可以通过对外暴露Promise的方式,使外部获得同步操作的能力 在原有例子上拓展,增加一个需要处理的更新时间属性
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// hooks/useWarehouse.js
function useWarehouse(admin) {
    const warehouse = reactive({ warehouseList: [] });
    const param = { id: admin.id, ...getParam() };
    const queryList = async () => {
        const { list, updateTime } = await queryWarehouse(param);
            list.forEach(goods=>{
        // 一些逻辑...
          return goods
        })
        warehouse.warehouseList = list;
        return updateTime;
    };
    return { ...toRefs(warehouse), queryList };
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export default useWarehouse;// components/Warehouse.vue
<template>
    <div>
       ...
        <span>nextUpdateTime:{{nextUpdateTime}}</span>
    </div>
</template>

<script>
...
import dayjs from 'dayjs';
export default defineComponent({
    setup() {
    ...
       // 仓库保管员
        const admin = {
            id: '1234',
            name: '张三',
            age: 28,
            sex: 'men',
        };
        const { warehouseList, queryList } = useWarehouse(admin);
        const nextUpdateTime = ref('');
        const interval = 7; // 假设更新仓库的时间间隔是7天
        const queryHandler = async () => {
            const updateTime = await queryList();
            nextUpdateTime.value = dayjs(updateTime).add(interval, 'day');
        };
        return { warehouseList, nextUpdateTime, queryHandler };
    },
});
</script>
  1. this的问题 因为setup是beforecreate阶段,不能获取到this,虽然通过setup的第二个参数context可以获得一部分的能力。是我们想要操作诸如路由,vuex这样的能力就收到了限制,最新的router@4、vuex@4都提供了组合式的api。

但是由于vue2的底层限制我们没有办法使用这些hook,但是我们可以通过引用实例的方式获得一定的操纵能力,也可以通过getCurrentInstance获得组件实例,上面挂载的对象。

由于composition-api中的响应式虽然底层原理与vue相同都是通过object.defineproperty改写属性实现的,但是具体实现方式存在差异,所以在setup当中与vue原生的响应式并不互通。这也导致即使我们拿到了相应的实例,也没有办法监听它们的响应式。如果有这方面的需求,只能在选项配置中使用。

总结

通过vue3组合式、与hook的能力。我们的代码风格有了很大的转变,逻辑更加聚合、纯粹。复用性能力得到了提升。项目整体的维护性有了显著的提高。这也是我们即便在vue2的项目中,也要使用composition-api引入vue3新特性的原因。若有收获,就点个赞吧

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-07-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端Q 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
前端开发行业真的会被AI取代吗?
相信不少人看过一篇人工智能已经能实现自动编写HTML,CSS的文章,人工智能开始取代前端的一部分工作。前端开发行业真的被人工智能取代吗?
AI科技大本营
2019/07/23
2.1K0
前端入门机器学习 Tensorflow.js 简明教程
写这篇文章的目的是给现有web开发的同事提供一些新的开发方向,认识新的js开发领域!
一只图雀
2020/11/03
4.3K0
前端入门机器学习 Tensorflow.js 简明教程
【TensorFlow开发者峰会】重磅发布TensorFlow.js,完全在浏览器运行机器学习
【新智元导读】北京时间3月31日举行的2018 TensorFlow 开发者峰会上,TensorFlow宣布重大更新:增加支持JavaScript,并推出开源库TensorFlow.js,用户可以完全在浏览器定义、训练和运行机器学习模型。谷歌大脑负责人Jeff Dean、TensorFlow 总监 Rajat Monga等人进行了Keynote演讲。 Jeff Dean主旨演讲:用超强大的计算力,替代ML专家 北京时间3月31日举行的2018 TensorFlow 开发者峰会上,Google Brain负责
新智元
2018/05/29
7070
面向纯新手的TensorFlow.js速成课程
本课程由CodingTheSmartWay.com出品,在本系列的第一部分中,你将学到:
AiTechYun
2018/09/26
7.4K1
面向纯新手的TensorFlow.js速成课程
TensorFlow从1到2(十五)(完结)在浏览器做机器学习
TensorFlow一直努力扩展自己的基础平台环境,除了熟悉的Python,当前的TensorFlow还实现了支持Javascript/C++/Java/Go/Swift(预发布版)共6种语言。 越来越多的普通程序员,可以容易的在自己工作的环境加入机器学习特征,让产品更智能。
俺踏月色而来
2019/05/17
9520
TensorFlow从1到2(十五)(完结)在浏览器做机器学习
【TensorFlow2.x开发—基础】 简介、安装、入门应用案例
本文介绍最新版本的TensorFlow开发与应用,目前最新版本是TensorFlow2.5.0;首先简单介绍一下TensorFlow,然后安装TensorFlow2,最后使用TensorFlow开发。
一颗小树x
2021/05/15
1.2K0
【TensorFlow2.x开发—基础】 简介、安装、入门应用案例
用 TensorFlow.js 在浏览器中训练神经网络
本文结构: 什么是 TensorFlow.js 为什么要在浏览器中运行机器学习算法 应用举例:regression 和 tflearn 的代码比较 ---- 1. 什么是 TensorFlow.js TensorFlow.js 是一个开源库,不仅可以在浏览器中运行机器学习模型,还可以训练模型。 具有 GPU 加速功能,并自动支持 WebGL 可以导入已经训练好的模型,也可以在浏览器中重新训练现有的所有机器学习模型 运行 Tensorflow.js 只需要你的浏览器,而且在本地开发的代码与发送给用户的代
杨熹
2018/06/21
1.4K0
【云+社区年度征文】浅谈 TensorFlow.js 在前端的工程化应用
Google 推出 TensorFlow.js 已有多年,JavaScript 也不知不觉成为了世界上最好的语言。相信对于大多数没接触过机器学习的前端工程师来说,都有一个共同的疑惑:TensorFlow.js 到底能做些什么?
CS逍遥剑仙
2020/11/14
3.8K0
Tensorflow实现在浏览器的深度学习
在最近的TensorFlow Dev Summit 2018大会上,Google宣布发布Tensorflow.js,这是用Javascript实现的开源深度学习框架Tensorflow。Tensorflow.js可以实现在浏览器中直接训练模型,通过使用WebGL JavaScript API获得更快的计算速度。 Tenforflow.js是由2017年8月Google发布的Javascript库deeplearn.js演化而来的。Deeplearn.js诞生于Tensorflow Playground这款由
程序你好
2018/07/20
3370
Github 项目推荐 | 面向 JS 开发者的机器学习框架 TensorFlow.js 以及相关示例
TensorFlow.js 是谷歌在 2018 TensorFlow 开发者峰会推出的开源库,它可以使用 Java 和灵活且直观的 API 在浏览器中定义、训练和运行机器学习模型。另外,TensorFlow.js 可以导入离线训练的 TensorFlow 和 Keras 模型进行预测,并可以对 WebGL 实现无缝支持。
AI研习社
2018/07/26
6490
Github 项目推荐 | 面向 JS 开发者的机器学习框架 TensorFlow.js 以及相关示例
基于TensorFlow.js在浏览器上构建深度学习应用
在前面的章节,我们讨论了各种JavaScript概念和运行在浏览器上的各种深度学习框架。在本章中,我们将所有的知识付诸于实践,证明该技术的潜力。
麒思妙想
2020/07/10
1.2K0
基于Tensorflow.js实现浏览器级别的目标识别应用实践
tensorflow.js 是谷歌于今年推出的浏览器级别的深度学习框架,TensorFlow 团队在其github官网上也公开了表示基于网页的 JavaScript 库 TensorFlow.js 库框架及其相关的例子。基于该应用能训练并部署机器学习模型。
sparkexpert
2019/05/26
9670
【开源】谷歌发布deeplearn.js,浏览器端的强大机器学习库
【新智元导读】谷歌最新发布 deeplearn.js 0.1.0,这是一个开源的 WebGL 加速的 JavaScript 机器学习库,完全在浏览器中运行,不需要安装,不需要后端处理。官网已经发布一系列demo,能力强大。 机器学习(ML)已经成为越来越强大的工具,可以应用于对象识别,语言翻译,医疗等各种领域。但是,使用常用的ML库,ML系统的发展往往局限于那些拥有计算资源和技术专长的人。 PAIR(People + AI Research initiative)是一个倡议研究和重新设计人类与ML交互的计划
新智元
2018/03/22
7830
【开源】谷歌发布deeplearn.js,浏览器端的强大机器学习库
【一统江湖的大前端(9)】TensorFlow.js 开箱即用的深度学习工具
TensorFlow是Google推出的开源机器学习框架,并针对浏览器、移动端、IOT设备及大型生产环境均提供了相应的扩展解决方案,TensorFlow.js就是JavaScript语言版本的扩展,在它的支持下,前端开发者就可以直接在浏览器环境中来实现深度学习的功能,尝试过配置环境的读者都知道这意味着什么。浏览器环境在构建交互型应用方面有着天然优势,而端侧机器学习不仅可以分担部分云端的计算压力,也具有更好的隐私性,同时还可以借助Node.js在服务端继续使用JavaScript进行开发,这对于前端开发者而言非常友好。除了提供统一风格的术语和API,TensorFlow的不同扩展版本之间还可以通过迁移学习来实现模型的复用(许多知名的深度学习模型都可以找到python版本的源代码),或者在预训练模型的基础上来定制自己的深度神经网络,为了能够让开发者尽快熟悉相关知识,TensorFlow官方网站还提供了一系列有关JavaScript版本的教程、使用指南以及开箱即用的预训练模型,它们都可以帮助你更好地了解深度学习的相关知识。对深度学习感兴趣的读者推荐阅读美国量子物理学家Michael Nielsen编写的《神经网络与深度学习》(英文原版名为《Neural Networks and Deep Learning》),它对于深度学习基本过程和原理的讲解非常清晰。
大史不说话
2020/04/21
1.1K0
【一统江湖的大前端(9)】TensorFlow.js 开箱即用的深度学习工具
TensorFlow.js 入门指南:让你的JavaScript应用拥有机器学习能力
随着机器学习技术的普及,不再仅限于Python和数据科学专家。通过TensorFlow.js,你可以将强大的机器学习能力带入你的JavaScript应用中。不论是网页、移动端还是桌面应用,集成机器学习都能显著提升功能性和用户体验。在本指南中,我们将探讨如何设置TensorFlow.js,构建和训练模型,并实现实际应用。
前端达人
2024/07/10
7330
TensorFlow.js 入门指南:让你的JavaScript应用拥有机器学习能力
快速入门TensorFlow.js指南
TensorFlow.JS,之前就发现这个好玩的东东,但是一直没有时间去看,作为一名深度学习者,没有折腾的心是不行的。我们都知道深度学习在工业和实际项目中有着很好的应用,但是如果用深度学习去做些有趣的应用也是很好玩的。
老潘
2023/10/19
3830
快速入门TensorFlow.js指南
教程 | 如何利用TensorFlow.js部署简单的AI版「你画我猜」图像识别应用
我们将使用卷积神经网络(CNN)来识别不同类型的手绘图像。这个卷积神经网络将在 Quick Draw 数据集(https://github.com/googlecreativelab/quickdraw-dataset)上接受训练。该数据集包含 345 个类别的大约 5 千万张手绘图像。
机器之心
2018/07/26
2K0
教程 | 如何利用TensorFlow.js部署简单的AI版「你画我猜」图像识别应用
使用TensorFlow.js进行时间序列预测
机器学习现在越来越受欢迎,越来越多的世界人口认为它是一个神奇的水晶球:预测未来何时以及将会发生什么。该实验使用人工神经网络揭示股市趋势,并展示时间序列预测根据过去的历史数据预测未来股票价格的能力。
代码医生工作室
2019/06/22
1.9K0
推荐几款很流行的面向 Javascript 的机器学习库
⭐️ 本文首发自 前端修罗场,是一个由资深开发者独立运行的专业技术社区,我专注 Web 技术、答疑解惑、面试辅导以及职业发展。帮你评估知识点的掌握程度,获得更全面的学习指导意见,交个朋友,不走弯路,少吃亏! ---- 最近公司在研发分布式高性能的云计算平台,其中涉及到了 AI 方面的处理。所以我也在自学 Machine Learning。不过在 AI 方面的知识却是需要花功夫花时间学习的。在学习的过程中我发现了一个不错的学习教程(https://www.captainai.net/iislv/),推荐给大
前端修罗场
2022/07/29
1.7K0
在TensorFlow2.0发布前,帮你掌握TensorFlow的必备内容
【导读】AI科技大本营曾报道过,TensorFlow 2.0 已经在开发计划中了,相信在不久的将来就会和我们见面。那么现在的 TensorFlow 都有哪些功能,大家是否都全部了解呢?近日,谷歌在 Google Cloud Next 上发布了关于TensorFlow 的所有新内容,AI科技大本营已经为你准备好了~
AI科技大本营
2018/09/28
9590
在TensorFlow2.0发布前,帮你掌握TensorFlow的必备内容
推荐阅读
相关推荐
前端开发行业真的会被AI取代吗?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档