在React中使用

整体来看,Edge 主题在 React 的支持情况要比 Vue 逊色一些,主要原因在于 React 自己构造一整套的事件处理机制,导致 LuLu UI 中部分 UI 组件的自定义事情没法直接套用 React 语法,需要借助 ref 手动添加事件,还有部分原因在于 React 有不少自己定义的规则。

  • 非 Web Components 元素使用 className 而不是 class
  • 部分表单元素 value 不能直接赋值,需要使用 defaultValue 属性;
  • 布尔属性一定要加 true,类似下面的代码就没有效果:
    <i is-tips title="内容">提示</i>

    必须明确指定 is-tips 属性值为 true

    <i is-tips="true" title="内容">提示</i>

我实在是不清楚为何 React 不按照 DOM 标准来设计,可能是跨端的野心,也可能是面向的开发群体是偏后,相比之下 Preact 则友好很多,同时采用原生的 DOM 事件系统,和 LuLu UI 完全一致,HTML 属性也是浏览器原生会泽,同时使用标签模板字面量开发了 htm,可以取代 JSX 的能力,可以在浏览器中直接使用。

所以,这里先示意如何在 Preact Web 免安装环境中使用 LuLu UI。

Preact与LuLu UI

先示意比较简单的日期范围选择组件,相关代码如下:

<div id="dateApp"></div>
<script type="module">
import { html, render } from 'https://unpkg.com/htm/preact/index.mjs?module'

function App (props) {
    return html`<input type="date" value="${props.value}" is="ui-datetime"/>`
}

render(html`<i is-tips title="支持标准HTML">日期:</i>
<${App} value="2021-08-17" />`, dateApp)
</script>

实时效果如下所示,可以看到日期可以正常选择:

事件

由于 Preact 是基于原生的 DOM 事件体系构建的,因此可以和 LuLu UI 无缝对接使用。

<div id="dateApp2"></div>
function OnChange (event) {
    dateApp2.querySelector('p').innerHTML = `选择的日期是:${event.target.value}`
}
function OnConnected (event) {
    event.target.after(` 今天是:${event.target.value}`)
}

render(html`<input onchange="${OnChange}" onconnected="${OnConnected}" is="ui-datetime" /><p></p>`, dateApp2)

实时效果如下所示,可以看到 LuLu UI 组件中自定义的 connected 事件触发了,当我们改变日期,原生的 change 事件也触发了。

传参

既然 Preact 和 LuLu UI 的事件体系完全一致,参数的传递处理就变得异常简单,和 Vue 中使用 LuLu UI 类似。

还是举数据列表的例子,代码如下所示。

<div id="listApp"></div>
// 传参设置
function setListData (event) {
    event.target.params.data = [{
        value: '蔡伦',
        userid: 1
    }, ... , {
        value: '彭玉乐',
        userid: 7
    }]
};
render(html`<input class="ui-input" is="ui-datalist" onconnected="${setListData}"/>`, listApp);

实时效果如下所示,点击输入框,可以看到选择列表出现了,功能都是正常的。

React与LuLu UI

虽然 LuLu UI 的气质和 React 不太相符,但是,绝大多数组件依然是可以无障碍使用的,并且相比 Vue 还有优势,那就是自定义元素组件天然支持。例如下面的 <ui-drop> 自定义元素组件在 React 中可以正常渲染,但是在 Vue 中会被警告处理:

<ui-drop target="t2" eventtype="hover">hover我</ui-drop>

下面通过几个典型例子,展示下如何在 React 框架开发环境中使用 LuLu UI,大家可以重点关注下自定义事件的处理。

假设你已经安装了 LuLu UI。

npm install lu2

表单控件

以最为基础的 <select> 控件举例。

相关代码如下所示:

<div id="root"></div>
import React from 'react';
import ReactDOM from 'react-dom';

import "lu2/theme/edge/css/common/ui/Select.css";
import "lu2/theme/edge/js/common/ui/Select.js";

function showValue (e) {
  console.log(`选中的值是:${e.target.value}`);
}

const select = (<select is="ui-select" defaultValue={3} onChange={showValue}>
<option value="1" disabled>选项1</option>
<option value="2">选项2</option>
<option value="3">选项3</option>
</select>)

ReactDOM.render(select, document.getElementById('root'));

效果截图示意:

由于 LuLu UI 中的 Select 组件基于原生 <select> 元素实现,全部都是 HTML 属性传参,事件也是浏览器原生的 change 事件,因此可以和 React 无障碍混合使用。

弹框

由于弹框大部分的使用场景都是使用 new 语法构造,因此,也是可以在 React 中无障碍使用的,类似组件还有 LightTip 轻提示。

使用示意,点击一个按钮出现 alert 提示框:

<div id="root"></div>
import "lu2/theme/edge/css/common/ui/Button.css";
import "lu2/theme/edge/css/common/ui/Dialog.css";
import Dialog from "lu2/theme/edge/js/common/ui/Dialog.js";

function showDialog () {
    new Dialog().alert('提示信息');
}

const button = <button type="primary" is="ui-button" onClick={showDialog}>弹框</button>

ReactDOM.render(button, document.getElementById('root'));

效果截图示意:

数据列表

在 Vue 以及 Preact 中,数据列表的参数可以通过 connected 事件进行设置,但是,React 由于自建事件机制,因此,无法触发 LuLu UI 内置的自定义事件,想要设置参数,就需要使用其他方法,例如 ref,使用示意:

<div id="root"></div>
import "lu2/theme/edge/css/common/ui/Input.css";
import "lu2/theme/edge/css/common/ui/Datalist.css";
import "lu2/theme/edge/js/common/ui/Datalist.js";

const myRef = React.createRef();
const datalist = <input class="ui-input" results="5" is="ui-datalist" ref={myRef}/>
// 组件 DOM 渲染
ReactDOM.render(datalist, document.getElementById('root'));

// 传参,此时 myRef.current 就是组件元素
const data = [{
  value: '蔡伦',
  userid: 1
}, ..., {
  value: '彭玉乐',
  userid: 7
}];

if (myRef.current.isConnectedCallback) {
  myRef.current.params.data = data;
} else {
  myRef.current.addEventListener('connected', function () {
    this.params.data = data
  });
}

效果截图示意:

表单验证

测试自定义属性

以上3个示例囊括了 LuLu UI 所有的 UI 组件类型,可以看出,LuLu UI Edge 主题绝对可以在 React 中使用的,只是较少部分组件的使用方式不那么优雅。

TypeScript与LuLu UI

由于 LuLu UI 并非基于某个框架集成的 UI 组件库,因此,对于对格式要求比较严苛的 TypeScript 环境,还需要一些额外的声明工作。

例如,可以在项目中新建一个名为 lu2.d.ts 的文件。然后——

自定义元素的声明,以下拉和选项卡元素举例:

declare namespace JSX {
  interface IntrinsicElements {
      "ui-tab": any;
  }
}
declare namespace JSX {
  interface IntrinsicElements {
      "ui-drop": any;
  }
}

自定义属性需要声明,例如(不是全部,仅示意):

declare namespace React {
  interface HTMLAttributes<T> {
      align?: string,
      open?: boolean,
      class?: string,
      maxlength?: string,
      name?: string,
  }
}

动态加载的 JS 模块也需要声明:

declare module 'lu2/theme/edge/js/common/ui/Tab.js' {}
declare module 'lu2/theme/edge/js/common/comp/Form.js' {}
declare module 'lu2/theme/edge/js/common/ui/LightTip.js' {}
...

全局实例对象也需要声明:

declare function LightTip();
declare function Dialog();

以上代码均是示意,并未包含所有组件,大家根据使用情况,自行添加即可。也欢迎提供完整版的 lu2.d.ts 文件。

本页贡献者:

zhangxinxu