@roundjs/composition-wx
TypeScript icon, indicating that this package has built-in type declarations

1.1.39 • Public • Published

@roundjs/composition-wx

说明

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

功能导航:

使用

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

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

Page

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

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-wx';

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-wx 是否会调用 onPageScroll() 钩子。

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

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-wx';

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-wx';

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-wx';

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-wx';

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-wx 提供了依赖注入功能,以解决 props 深度透传的问题。它们是一对 provide / inject 函数,它们的使用方式和 API 均与 Vue 一致。

Provide

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

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-wx';

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-wx';

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

Readme

Keywords

none

Package Sidebar

Install

npm i @roundjs/composition-wx

Weekly Downloads

1

Version

1.1.39

License

MIT

Unpacked Size

598 kB

Total Files

10

Last publish

Collaborators

  • li13