refactor: 确立独立子工程架构 (backend, admin, mpuniapp) 并同步更新 AGENTS.md 规范
这个提交包含在:
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<!--建议只存在一个根节点,如果native-view存在兄弟节点则需要将其包裹处理-->
|
||||
<view>
|
||||
<native-view style="height: 100px;" @init="onviewinit" @customClick="ontap"></native-view>
|
||||
<button style="width: 50%;margin: 10px 0px;align-self: center;">测试按钮</button>
|
||||
</view>
|
||||
</template>
|
||||
<script setup lang="uts">
|
||||
import { NativeButton } from "@/uni_modules/native-button";
|
||||
let button : NativeButton | null = null
|
||||
|
||||
//声明属性
|
||||
const props = defineProps<{ text : string }>()
|
||||
|
||||
//声明事件
|
||||
const emit = defineEmits<{
|
||||
(e : "load") : void
|
||||
(e : "buttonTap", event : UniNativeViewEvent) : void
|
||||
}>()
|
||||
|
||||
//声明方法
|
||||
function updateText(value : string) {
|
||||
button?.updateText(value)
|
||||
}
|
||||
|
||||
//监听属性变化
|
||||
watchEffect(() => {
|
||||
const text = props.text
|
||||
updateText(text)
|
||||
})
|
||||
|
||||
/**
|
||||
* native-view组件初始化时触发
|
||||
* 用于绑定App平台原生View
|
||||
*/
|
||||
function onviewinit(e : UniNativeViewInitEvent) {
|
||||
//获取UniNativeViewElement 传递给NativeButton对象
|
||||
button = new NativeButton(e.detail.element);
|
||||
updateText(props.text)
|
||||
emit("load")
|
||||
}
|
||||
|
||||
/**
|
||||
* 将native-view组件的ontap事件转换为buttonTap事件
|
||||
*/
|
||||
function ontap(e : UniNativeViewEvent) {
|
||||
emit("buttonTap", e)
|
||||
}
|
||||
|
||||
/**
|
||||
* App平台需要主动释放资源
|
||||
*/
|
||||
onUnmounted(() => {
|
||||
button?.destroy()
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"id": "native-button",
|
||||
"displayName": "native-button",
|
||||
"version": "0.0.1",
|
||||
"description": "vue开发button原生组件",
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^4.25"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "uts",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "插件不采集任何数据",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "n",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-android": {
|
||||
"minVersion": "21"
|
||||
},
|
||||
"app-ios": {
|
||||
"minVersion": "9"
|
||||
}
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "u",
|
||||
"QQ": "y",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
## native-button
|
||||
|
||||
通过 object 封装原生平台Button按钮
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"minSdkVersion": "21"
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import Button from "android.widget.Button"
|
||||
import { INativeButtonContext, CreateNativeButtonContext } from "../interface.uts"
|
||||
|
||||
export class NativeButton {
|
||||
$element : UniNativeViewElement;
|
||||
|
||||
constructor(element : UniNativeViewElement) {
|
||||
//接收传递过来的UniNativeViewElement
|
||||
this.$element = element;
|
||||
this.bindView();
|
||||
}
|
||||
|
||||
button : Button | null = null;
|
||||
bindView() {
|
||||
//通过UniElement.getAndroidActivity()获取android平台activity 用于创建view的上下文
|
||||
this.button = new Button(this.$element.getAndroidActivity()!); //构建原生view
|
||||
//限制原生Button 文案描述不自动大写
|
||||
this.button?.setAllCaps(false)
|
||||
//监听原生Button点击事件
|
||||
this.button?.setOnClickListener(_ => {
|
||||
const detail = {
|
||||
value: "CustomValue"
|
||||
}
|
||||
//构建自定义UniNativeViewEvent返回对象
|
||||
const event = new UniNativeViewEvent("customClick", detail)
|
||||
//触发原生Button的点击事件
|
||||
this.$element.dispatchEvent(event)
|
||||
})
|
||||
//UniNativeViewEvent 绑定 安卓原生view
|
||||
this.$element.bindAndroidView(this.button!);
|
||||
}
|
||||
|
||||
updateText(text : string) {
|
||||
//更新原生Button 文案描述
|
||||
this.button?.setText(text)
|
||||
}
|
||||
|
||||
|
||||
destroy() {
|
||||
//数据回收
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class NativeButtonContext implements INativeButtonContext {
|
||||
private element : UniElement | null = null
|
||||
|
||||
constructor(element : UniElement) {
|
||||
this.element = element
|
||||
}
|
||||
updateText(text : string) {
|
||||
let button = this.element?.getAndroidView()
|
||||
if(null != button){
|
||||
(button as Button).setText(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 递归查询
|
||||
*/
|
||||
function iterateElement(homeElement : UniElement) : UniElement | null {
|
||||
if ("NATIVE-VIEW" == homeElement.nodeName) {
|
||||
return homeElement
|
||||
}
|
||||
for (perChildEle of homeElement.children) {
|
||||
let findEle = iterateElement(perChildEle)
|
||||
if (findEle != null) {
|
||||
return findEle
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function createNativeButtonContext(id : string, ins : ComponentPublicInstance | null = null) : INativeButtonContext | null {
|
||||
if (ins == null) {
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length > 0) {
|
||||
const page = pages[pages.length - 1]
|
||||
const rootViewElement = page.getElementById(id)
|
||||
if (rootViewElement != null) {
|
||||
/**
|
||||
* 找到了root节点,递归检索目标 native-view
|
||||
*/
|
||||
const nativeViewElement = iterateElement(rootViewElement)
|
||||
if (nativeViewElement != null) {
|
||||
return new NativeButtonContext(nativeViewElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* 尝试迭代遍历
|
||||
*/
|
||||
if (ins.$el != null) {
|
||||
const nativeViewElement = iterateElement(ins.$el as UniElement)
|
||||
if (nativeViewElement != null) {
|
||||
return new NativeButtonContext(nativeViewElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
@Builder
|
||||
export function buildButton(params: ESObject) {
|
||||
Button(params.text, { type: ButtonType.Normal, stateEffect: true })
|
||||
.borderRadius(8)
|
||||
.backgroundColor(0x317aff)
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.onClick(() => {
|
||||
params.onClick()
|
||||
})
|
||||
.attributeModifier(params.attributeUpdater)
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
import { BuilderNode } from "@kit.ArkUI"
|
||||
// 导入混编实现的声明式UI构建函数
|
||||
import { buildButton } from "./builder.ets"
|
||||
|
||||
import { INativeButtonContext } from "../interface.uts"
|
||||
// 定义 buildButton 的参数类型
|
||||
interface NativeButtonOptions {
|
||||
text : string
|
||||
onClick : () => void
|
||||
}
|
||||
|
||||
export class NativeButton {
|
||||
private $element : UniNativeViewElement;
|
||||
private builder : BuilderNode<[NativeButtonOptions]> | null = null
|
||||
// 初始化 buildButton 默认参数
|
||||
private params : NativeButtonOptions = {
|
||||
text: '',
|
||||
onClick: () => {
|
||||
const detail = {
|
||||
value: "CustomValue"
|
||||
}
|
||||
this.$element.dispatchEvent(new UniNativeViewEvent("customClick", detail))
|
||||
}
|
||||
}
|
||||
|
||||
constructor(element : UniNativeViewElement) {
|
||||
// 绑定 wrapBuilder 函数
|
||||
this.builder = element.bindHarmonyWrappedBuilder(wrapBuilder<[NativeButtonOptions]>(buildButton), this.params)
|
||||
this.$element = element
|
||||
// 绑定当前实例为自定义的controller,方便其他地方通过 element 获取使用
|
||||
this.$element.bindHarmonyController(this)
|
||||
}
|
||||
|
||||
updateText(text : string) {
|
||||
this.params.text = text
|
||||
// 调用 builder update 函数来更新 UI
|
||||
this.builder?.update(this.params)
|
||||
}
|
||||
|
||||
destroy() {
|
||||
//数据回收
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class NativeButtonContext implements INativeButtonContext {
|
||||
private controller : NativeButton
|
||||
constructor(element : UniNativeViewElement) {
|
||||
// 获取自定义的 controller
|
||||
this.controller = element.getHarmonyController<NativeButton>()!
|
||||
}
|
||||
updateText(text : string) {
|
||||
// 调用 controller 来更新文字
|
||||
this.controller?.updateText(text)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 递归查询
|
||||
*/
|
||||
function iterateElement(homeElement : UniElement) : UniNativeViewElement | null {
|
||||
if ("NATIVE-VIEW" == homeElement.nodeName) {
|
||||
return homeElement as UniNativeViewElement
|
||||
}
|
||||
for (const perChildEle of homeElement.children) {
|
||||
let findEle = iterateElement(perChildEle)
|
||||
if (findEle != null) {
|
||||
return findEle
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function createNativeButtonContext(id : string, ins : ComponentPublicInstance | null = null) : INativeButtonContext | null {
|
||||
if (ins == null) {
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length > 0) {
|
||||
const page = pages[pages.length - 1]
|
||||
const rootViewElement = page.getElementById(id)
|
||||
if (rootViewElement != null) {
|
||||
/**
|
||||
* 找到了root节点,递归检索目标 native-view
|
||||
*/
|
||||
const nativeViewElement = iterateElement(rootViewElement)
|
||||
if (nativeViewElement != null) {
|
||||
return new NativeButtonContext(nativeViewElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* 尝试迭代遍历
|
||||
*/
|
||||
if (ins.$el != null) {
|
||||
const nativeViewElement = iterateElement(ins.$el as UniElement)
|
||||
if (nativeViewElement != null) {
|
||||
return new NativeButtonContext(nativeViewElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"deploymentTarget": "12"
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import { UIButton, UIControl } from "UIKit"
|
||||
import { INativeButtonContext, CreateNativeButtonContext } from "../interface.uts"
|
||||
import { CGFloat } from 'CoreFoundation';
|
||||
|
||||
|
||||
export class NativeButton {
|
||||
|
||||
element : UniNativeViewElement;
|
||||
button : UIButton | null = null;
|
||||
|
||||
constructor(element : UniNativeViewElement) {
|
||||
// 接收组件传递过来的UniNativeViewElement
|
||||
this.element = element;
|
||||
super.init()
|
||||
this.bindView();
|
||||
}
|
||||
|
||||
// element 绑定原生view
|
||||
bindView() {
|
||||
// 初始化原生 UIButton
|
||||
this.button = new UIButton(type=UIButton.ButtonType.system)
|
||||
// 构建方法选择器
|
||||
const method = Selector("buttonClickAction")
|
||||
// button 绑定点击回调方法
|
||||
button?.addTarget(this, action = method, for = UIControl.Event.touchUpInside)
|
||||
// UniNativeViewElement 绑定原生 view
|
||||
this.element.bindIOSView(this.button!);
|
||||
}
|
||||
|
||||
updateText(text : string) {
|
||||
// 更新 button 显示文字
|
||||
this.button?.setTitle(text, for = UIControl.State.normal)
|
||||
}
|
||||
|
||||
/**
|
||||
* 按钮点击回调方法
|
||||
* 在 swift 中,所有target-action (例如按钮的点击事件,NotificationCenter 的通知事件等)对应的 action 函数前面都要使用 @objc 进行标记。
|
||||
*/
|
||||
@objc buttonClickAction() {
|
||||
//构建自定义 UniNativeViewEvent 对象
|
||||
const detail = {
|
||||
value: "CustomValue"
|
||||
}
|
||||
let event = new UniNativeViewEvent("customClick", detail)
|
||||
//触发自定义事件
|
||||
this.element.dispatchEvent(event)
|
||||
}
|
||||
|
||||
destroy() {
|
||||
// 释放 UTS 实例对象,避免内存泄露
|
||||
UTSiOS.destroyInstance(this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getNativeViewElemet(element: UniElement | null): UniNativeViewElement | null {
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
if (element instanceof UniNativeViewElement) {
|
||||
return element as UniNativeViewElement
|
||||
}
|
||||
for (item in element!.children) {
|
||||
let tmp = getNativeViewElemet(item)
|
||||
if (tmp != null) {
|
||||
return tmp
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
export const createNativeButtonContext: CreateNativeButtonContext = function (id : string, component ?: ComponentPublicInstance | null) : INativeButtonContext | null {
|
||||
let element : UniNativeViewElement | null = null;
|
||||
let e: UniElement | null = null;
|
||||
if (component == null) {
|
||||
e = uni.getElementById(id)
|
||||
} else {
|
||||
e = component?.$el as UniElement | null;
|
||||
}
|
||||
if (e instanceof UniNativeViewElement) {
|
||||
element = e as UniNativeViewElement | null
|
||||
}else {
|
||||
element = getNativeViewElemet(e)
|
||||
}
|
||||
|
||||
if (element == null) return null;
|
||||
return new NativeButtonContextImpl(element!);
|
||||
}
|
||||
|
||||
|
||||
class NativeButtonContextImpl implements INativeButtonContext {
|
||||
btn: UIButton | null = null
|
||||
constructor(element : UniNativeViewElement) {
|
||||
let view = element.getIOSView()
|
||||
if (view != null) {
|
||||
this.btn = view as UIButton
|
||||
}
|
||||
}
|
||||
updateText(title: string) : void {
|
||||
this.btn?.setTitle(title, for = UIControl.State.normal)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 原生组件的上下文对象
|
||||
*/
|
||||
export interface INativeButtonContext {
|
||||
/**
|
||||
* 更新文本示例
|
||||
*/
|
||||
updateText(text : string) : void
|
||||
}
|
||||
|
||||
export type CreateNativeButtonContext = (
|
||||
id : string,
|
||||
component ?: ComponentPublicInstance | null
|
||||
) => INativeButtonContext | null;
|
||||
在新工单中引用
屏蔽一个用户