Unified Component: Write once component, Run in multiple lib/platform.
Depend on @uni-store.
Unified Component core parts:
setup, like vue setup, just define the component state. The state can be used to any platforms. This should be contained pure component state logic.render, optional. This should be used when platform support render function, like : web platform or miniapp which supported runtime render.
Usage cases:
Refactor vuetify@next with uni-component.
Or see components for more uni-component usage cases.
pnpm add @uni-component/core
# or with yarn
yarn add @uni-component/core
# or with npm
npm install @uni-component/coreMore cases, see @uni-component/components.
import{h,PropType,uniComponent}from'@uni-component/core'import{computed,ref}from'@uni-store/core'// pure setup stateexportconstUniButton=uniComponent('uni-button',{type: {type: StringasPropType<'button'|'submit'|'reset'>,default: 'button'},text: String,icon: String,primary: Boolean,onClick: FunctionasPropType<(e?: MouseEvent)=>any>},(name,props)=>{constn=ref(0)constrootClass=computed(()=>{return{[`${name}-primary`]: props.primary}})constclickAction=(e?: MouseEvent)=>{n.value+=1// do othersprops.onClick&&props.onClick(e)}return{
n,
rootClass,
clickAction
}})// platform component with pure render functionexportconstCubeButtonxx=uni2Platform(UniButton,(props,state,{ renders })=>{const{ type, text }=props// rootClass always contain Component name, like 'cube-button'const{ rootClass, n, clickAction }=stateconstt=text ? text : (renders.defaultRender&&renders.defaultRender())return(<buttonclass={rootClass}type={type}onClick={clickAction}><span>{ t }{ n }</span></button>)})Install:
pnpm add @uni-component/vue
# or with yarn
yarn add @uni-component/vue
# or with npm
npm install @uni-component/vueUse:
/// <reference types="@uni-component/vue/platform" />import{h,Fragment}from'@uni-component/core'import'@uni-component/vue'import{createApp}from'vue'constApp=()=>{return(<><CubeButton>child</CubeButton><CubeButtonprimary={true}text='text'></CubeButton></>)}createApp(App).mount('#root')JSX with tsconfig: { "jsxFactory": "h", "jsxFragmentFactory": "Fragment" }
Install:
pnpm add @uni-component/react
# or with yarn
yarn add @uni-component/react
# or with npm
npm install @uni-component/reactUse:
/// <reference types="@uni-component/react/platform" />import{h,Fragment}from'@uni-component/core'import'@uni-component/react'importReactDOMfrom'react-dom'constApp=()=>{return(<><CubeButton>child</CubeButton><CubeButtonprimary={true}text='text'></CubeButton></>)}ReactDOM.render(<App/>,document.getElementById('root'))JSX with tsconfig: { "jsxFactory": "h", "jsxFragmentFactory": "Fragment" }
In my opinion, the pure state is a headless component.
Use uniComponent API.
Object props:
import{uniComponent,classNames,UniNode,PropType}from'@uni-component/core'constUniXxYy=uniComponent('uni-xx-yy',{type: {type: StringasPropType<'button'|'submit'|'reset'>,default: 'button'},text: String,icon: String,primary: Boolean,onClick: FunctionasPropType<(e?: MouseEvent)=>any>,xxRender: FunctionasPropType<(param: {})=>UniNode|undefined>,},(name,props,context)=>{// name is 'UniXxYy'constn=ref(0)constrootClass=computed(()=>{return{[`${name}-primary`]: props.primary}})// other class you should always use classNamesconstotherClass=computed(()=>{returnclassNames({[`${name}-child-xx`]: props.type==='reset'})})constclickAction=(e?: MouseEvent)=>{n.value+=1// do othersprops.onClick&&props.onClick(e)}return{
n,
rootClass,
clickAction
}})Notice: xxRender prop will be treated as render function(React - render function, vue - scope slot)
Array props:
constUniXxYy=uniComponent('uni-xx-yy',['a','b'],(name,props,context)=>{// name is 'UniXxYy'// props.a and props.b can be any value// ...return{// ...}})No props:
constUniXxYy=uniComponent('uni-xx-yy',(name,props,context)=>{// name is 'UniXxYy'// ...return{// ...}})About context param
{// renders contained all `xxRender` in props// renders.defaultRender() is used to replace `props.children` in react and `slots.default` in vue
renders: Record<string,(...args: any[])=>any>// all element attrs, no ref and key
attrs: Record<string,any>// element attrs without `class, style, id`
$attrs: Record<string,any>// original props setted by usage case// without default propsnodeProps?: Record<string,any>|null}This is optional.
Use uni2Platform(UniComponent, render: (props, state, context) => UniNode | undefined) API.
UniComponentheadless component, theuniComponent()resultrender()pure render function.- About
stateparam{rootClass: string,rootStyle: {[key: string]: 'string value'},rootId: string|undefined// other state with your custom state// n,// xxAction,//...}
- About
Demo:
// platform component with pure render functionconstXxYy=uni2Platform(UniXxYy,(props,state,{ renders })=>{const{ type, text }=props// rootClass always contain Component name, like 'uni-xx-yy'const{ rootClass, rootStyle, rootId, n, clickAction }=stateconstt=text ? text : (renders.defaultRender&&renders.defaultRender())return(<buttonid={rootId}class={rootClass}style={rootStyle}type={type}onClick={clickAction}><span>{t}{n}</span></button>)})Use useRef API and ref attribute.
import{useRef}from'@uni-component/core'constUniXxYy=uniComponent('uni-xx-yy',(name)=>{// name is 'UniXxYy'constele=ref<HTMLElement>()constsetEleRef=useRef(ele)// buttonComponent will be the state of CubeButton// defined in UniButtonconstbuttonComponent=ref<{n: number,clickAction: (e?: MouseEvent)=>void}>()constsetButtonComponentRef=useRef(buttonComponent)return{
setEleRef,
setButtonComponentRef,}})render:
constXxYy=uni2Platform(UniXxYy,(props,state)=>{const{ setEleRef, setButtonComponentRef }=statereturn(<divref={setEleRef}><CubeButtonref={setButtonComponentRef}>xx</CubeButton></div>)})Notice: The ref value will be this component's state result when referenced a component
Only 3 lifecycles: mounted, updated and unmounted.
import{onMounted,onUpdated,onUnmounted}from'@uni-component/core'constUniXxYy=uniComponent('uni-xx-yy',(name)=>{onMounted(()=>{console.log('mounted')})onUpdated(()=>{console.log('updated')})onUnmounted(()=>{console.log('unmounted')})return{// ...}})Like vue 3 Provide / Inject.
Provide:
// parent componentimport{provide}from'@uni-component/core'constUniXxYy=uniComponent('uni-xx-yy',(name)=>{provide('xx-key',{// xx: xxValue// ...})return{// ...}})Inject:
// child componentimport{inject}from'@uni-component/core'constUniXxYyChild=uniComponent('uni-xx-yy-child',(name)=>{// const xxProvide = inject('xx-key')// with default valueconstxxYyProvideValue=inject('xx-key',{// xx: defaultValue// ...})return{// ...}})classNames(), process element class names. Same as classnames.const mergedStyle = mergeStyle(stringStyle, objectStyle, ...(string or object styles)), merge styles.mergedStyleis an object.