npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@roundjs/composition-ali

v1.1.37

Published

支付宝小程序组合式api

Downloads

43

Readme

@roundjs/composition-ali

说明

@roundjs/composition-ali 是基于 reactivity api 的小程序开发库,它能让你用 Composition API 写小程序,就像写 Vue 3 一样。

功能导航:

使用

npm i @roundjs/composition-ali
# or
yarn add @roundjs/composition-ali

(ps:1.1.xx之后的版本使用方式 由Page(createPage()) 改为更简洁的直接 createPage())

Page

import { createPage, reactive, computed } from '@roundjs/composition-ali';

createPage({
  setup() {
    const state = reactive({
      count: 0,
      double: computed(() => state.count * 2),
    });

    function increment() {
      state.count++;
    }

    return {
      state,
      increment,
    };
  },
});

在使用上为了不影响原小程序语法,先使用 createPage 包装一层:

Page(obj) -> createPage(obj)

如果 setup 返回一个对象,则对象的属性将会被合并到页面实例上,可以直接在页面模版中使用。

<button onTap="increment">
  Count is: {{ state.count }}, double is: {{ state.double }}
</button>

注意 setup 返回的 ref 在模板中会自动解开,不需要写 .value

setup

  • 调用时机

setup 会在 onLoad 阶段被调用。返回的数据和方法也会在此时才会被合并到页面实例上,所以模版初次渲染时数据可能是 undefined。不过小程序模版对此做了兼容,所以不用担心会报错。

  • 参数

setup 函数的第一个参数与 onLoad 的参数相同。

createPage({
  setup(query) {
    // query 为打开当前页面路径中的参数
  },
});

生命周期

生命周期对应关系:

import { createPage, onShow, onHide, onUnload } from '@roundjs/composition-ali';

createPage({
  setup() {
    onShow(() => {
      console.log('show');
    });
    onHide(() => {
      console.log('hide');
    });
    onUnload(() => {
      console.log('unload');
    });
  },
});

| 原生 | 组合式 api | | :---------------: | :---------------: | | onLoad | setup | | onShow | onShow | | onReady | onReady | | onHide | onHide | | onUnload | onUnload | | onTitleClick | onTitleClick | | onReachBottom | onReachBottom | | onPullDownRefresh | onPullDownRefresh | | onShareAppMessage | onShareAppMessage | | onPageScroll | onPageScroll | | onTabItemTap | onTabItemTap |

为了兼容自定义hooks,页面也可以使用 onMountedonUnmounted 生命周期

createPage 第二个参数为配置项,以下两个生命周期需要配置才可生效

  • onPageScroll
  • onShareAppMessage

onPageScroll

监听页面滚动会引起小程序渲染层与逻辑层的通信。为避免定义空的 onPageScroll 监听造成不必要的性能损耗,需要使用 createPage 的第二个参数提前告知 composition-ali 是否会调用 onPageScroll() 钩子。

import { createPage, onPageScroll } from '@roundjs/composition-ali';

createPage(
  {
    setup() {
      onPageScroll(({ scrollTop }) => {
        console.log('scrollTop:', scrollTop);
      });
    },
  },
  {
    listenPageScroll: true, // 默认为 false
  }
);

onShareAppMessage

由于小程序会根据是否定义了 onShareAppMessage 监听来决定页面是否可以转发,所以需要使用 createPage 的第二个参数提前告知 Vue Mini 是否会调用 onShareAppMessage() 钩子。又由于 onShareAppMessage 会返回自定义转发内容,所以一个页面只能有一个 onShareAppMessage 监听。

import { createPage, onShareAppMessage } from '@roundjs/composition-ali';

createPage(
  {
    setup() {
      // 仅第一次调用,且 `canShareToOthers` 为 `true`,且 `onShareAppMessage` 选项不存在时才生效。
      onShareAppMessage(() => {
        return {
          title: '小程序示例',
          desc: '小程序官方示例Demo,展示已支持的接口能力及组件。',
          path: 'page/component/component-pages/view/view?param=123',
        };
      });
    },
  },
  {
    canShareToOthers: true, // 默认为 false
  }
);

原生混用

import { createPage, ref } from '@roundjs/composition-ali';

createPage({
  setup() {
    const count = ref(0);

    function increment() {
      count.value++;
    }

    return {
      count,
      increment,
    };
  },
  data: {
    number: 0,
  },
  add() {
    this.setData({ number: this.data.number + 1 });
  },
});

如果名称相同,setup() 返回的数据或方法会覆盖原生语法声明的数据或方法。你应该避免出现这种情况。

请不要在其他选项中访问 setup() 返回的数据或方法,这将引起混乱。如果确实有此需求,应该将相关逻辑搬到 setup() 内。

简洁语法

createPage(() => {
  const count = ref(0);

  function increment() {
    count.value++;
  }

  return {
    count,
    increment,
  };
});

Component

组件 setup 函数第一个参数为 props(跟 vue3 一样,不可解构使用) 第二个参数包含emit方法向父组件通知

propsemits 参照vue3的使用

(注意props声明方式跟原生小程序写法不一样)

import { createComponent, watch } from '@roundjs/composition-ali';

createComponent({
  emits: ['change'],
  props: {
    count: {
      default: 0
    },
  },
  setup(props, { emit }) {
    console.log(props.count)

    watch(
      () => props.count,
      (val) => {
        emit('change')
        console.log('watch props.count', val)
      }
    );

    const count = computed(() => props.count * 2);

    return {
      count,
    };
  },
});

生命周期

生命周期对应关系:

| 原生 | 组合式 api | | :--------: | :---------: | | didMount | setup | | didMount | onMounted | | didUpdate | onUpdated | | didUnmount | onUnmounted | | onError | onError |

页面声明周期

组件可使用部分页面的声明周期: onShow onHide onPullDownRefresh onReachBottom onPageScroll onTabItemTap

在组件里使用onShow时可能会错过初次的onShow调用

App

import { createApp } from '@roundjs/composition-ali';

createApp({
  setup() {
    const greeting = 'Hello World!';

    return {
      greeting,
    };
  },
});

注意

createApp 需要注意,setup 返回的对象不会经过处理,依然是响应式

返回什么就是什么:

createApp({
  setup() {
    const greeting = ref('Hello World!');

    return {
      greeting,
    };
  },
});

const app = getApp();

console.log(app.greeting.value); // Hello World!

生命周期

生命周期对应关系:

| 原生 | 组合式 api | | :------------------: | :------------------: | | onLaunch | setup | | onShow | onAppShow | | onHide | onAppHide | | onError | onAppError | | onPageNotFound | onPageNotFound | | onUnhandledRejection | onUnhandledRejection |

响应式 api

响应式 api 跟 vue3 使用相同,可参考 响应式 api 文档

响应性基础 API

  • reactive
  • readonly
  • isProxy
  • isReactive
  • isReadonly
  • toRaw
  • markRaw
  • shallowReactive
  • shallowReadonly

Refs

  • ref
  • unref
  • toRef
  • toRefs
  • isRef
  • customRef
  • shallowRef
  • triggerRef

Computed 与 watch

  • computed
  • watchEffect
  • watchPostEffect
  • watchSyncEffect
  • watch

watch参数 flush: 'post' 或者 使用watchPostEffect api,可在数据改变并且小程序页面完成渲染后触发回调)

Effect 作用域 API

  • effectScope
  • getCurrentScope
  • onScopeDispose

hooks

useNextTick

{
  setup() {
    const nextTick = useNextTick()
    const count = ref(0)

    const changeCount = () => {
      count.value++
      nextTick(() => {
        // dom更新后
      })

      await nextTick()
    }
  }
}

也可从setupcontext中引入

{
  setup(xxx, { nextRender }) {
    const count = ref(0)

    const changeCount = () => {
      count.value++
      nextRender(() => {
        // dom更新后
      })

      await nextRender()
    }
  }
}

useApp

跟小程序的getApp不一样的是可在createAppsetup里使用

依赖注入

Vue 一样,composition-ali 提供了依赖注入功能,以解决 props 深度透传的问题。它们是一对 provide / inject 函数,它们的使用方式和 API 均与 Vue 一致。

Provide

// parent-component.js
import {
  createComponent,
  ref,
  provide,
  readonly,
} from '@roundjs/composition-ali';

createComponent({
  setup() {
    const count = ref(0);

    function increment() {
      count.value++;
    }

    provide('count', readonly(count));
    provide('increment', increment);
  },
});

Inject

// deep-child-component.js
import { createComponent, inject } from '@roundjs/composition-ali';

createComponent({
  setup() {
    const count = inject('count');
    const increment = inject('increment');

    return {
      count,
      increment,
    };
  },
});

注意 依赖注入对执行顺序有所要求,provide 必须先于 inject 执行,所以在 createPagesetup 函数中调用 provide 可能会遇到问题。

AOP

AOP(切面编程),主要对 App/Page/Component 内方法调用进行统一劫持,可用于埋点,链路分析,日志等功能

import { aop, setupAOP } from '@roundjs/composition-ali';

const pageAop = aop(
  {
    onLoad(args, name) {
      console.log('所有页面onLoad调用之前都会触发', args);
    },
    onShareAppMessage: {
      after(result, args, name) {
        console.log(`${name}方法被调用之后,after一般获取函数返回值操作`);
        return result;
      },
    },
  },
  (args, name) => {
    console.log('other 其他函数调用');
  }
);

// 装载全局,要在createApp/createPage/defineComponent之前调用
setupAOP(({ page, app, component }) => {
  page.add(pageAop);
});
  • aop(AopOptions, Other)
  • aop(Other)

aop 方法有两个参数,AopOptions代码劫持某一具体函数,Other代表劫持除了AopOptions内声明的其他函数

可以只传入Other来劫持所有函数调用

after请务必返回result结果

aop 函数只会劫持一层对象,如需多层可用以下写法:

aop({
  onShow(args, name) {} // 函数形式默认 before
  onHide: { // 对象形式 before after
    before(args, name) {}
    after(result, args, name) {return result}
  }
  methods: aop({ // 深度劫持
    handleClick(args, name) {}
  })
}, {
  before(args, name) => { // Other 也可以写成对象形式,可通过name来判断对象名
    console.log('除了onShow,onHide的方法都会触发Other')
  }
})

优化路径

可通过修改配置参数来启用优化路径模式

import { setGlobalConfig, createPage } from '@roundjs/composition-wx';

// 全局配置
setGlobalConfig({
  optimizePath: true,
});

// or

// 优先级更高的局部配置
createPage({ setup() {} }, { optimizePath: true });
createComponent({ setup() {} }, { optimizePath: true });

createPagecreateComponent 上配置优先级更高,会先取示例上的配置,然后取全局配置

启用 优化路径 模式后,setData会采用路径形式来修改数据,例:

list[0].deep.name = 'xxx'

这个修改中,如果不启用 optimizePath 则默认修改的是整个 listsetData({ list }),如果 list 数据过长就会造成性能下降

如果启用 optimizePath 则会精确修改变动值 setData({ 'list[0].deep.name': 'xxx' }),从而提高 setData 性能

ps:因为optimizePath 模式会多出来 diff 数据的时间,实际上会比原生 setData({ 'list[0].deep.name': 'xxx' }) 慢,但是比不启用optimizePath直接 setData({list})更快

参考

vue-mini