openkraken / kraken

A web standards-compliant, high-performance rendering engine based on Flutter.
https://openkraken.com
Apache License 2.0
4.93k stars 304 forks source link

自定义的widget是否能通过调用js得到想要的Widget #1399

Open zjt123 opened 2 years ago

zjt123 commented 2 years ago

使用场景 | Use case

自定义的widget是否能通过调用js得到想要的Widget, 目前看文档dart和js通讯好像做不到类似的 例如自定义了一个 widget, widget里面对业务逻辑的处理,但是ui需要通过调用js得到的,js根据业务数据来生成对应的ui a、b、c..等

提案 | Proposal

伪代码例子:

Kraken.defineCustomElement('k-demo-element2',
    (context) {
  return DemoElement2(context);
});

class DemoElement2 extends WidgetElement { List dataList = [{"name":"1", "style":"1"}, {"name":"2", "style":"2"}, {"name":"3", "style":"3"}];

DemoElement2(context) : super(context, defaultStyle: {'display': 'block'}); @override Widget build(BuildContext context, Map<String, dynamic> properties, List children) { return Container( color: Colors.blue, width: 300, height: 500, child:CustomScrollView( slivers: [SliverList( delegate: SliverChildBuilderDelegate( (_, index) => _ListWidget(index), childCount: dataList.length, )])); }

_ListWidget(index) { // dataList[index] , 根据数据调用js,能否得到一个StyleWidget ??? return StyleWidget; } dynamic sayHi(List args) { print(args); print(args[0]); print(args[0].runtimeType); }

@override getBindingProperty(String key) { if (key == 'sayHi') { return sayHi; }

return super.getBindingProperty(key);

} }

answershuto commented 2 years ago

用 JS 就是通过 document.createElement 创建一个新的 custom element。

zjt123 commented 2 years ago

用 JS 就是通过 document.createElement 创建一个新的 custom element。

那怎么返回给这个WidgetElement呢? appendChild?

answershuto commented 2 years ago

嗯, appendChild 后,子 Element 会传递到 WidgetElement 的 build 中,chidren 参数会带上。

zjt123 commented 2 years ago

嗯, appendChild 后,子 Element 会传递到 WidgetElement 的 build 中,chidren 参数会带上。

我现在是这么弄的,但是把childen放到列表里面就会有问题,滚动也有问题,感觉自定义的WidgetElement列表和KrakenElementToWidgetAdaptor不兼容。可以看我给出来的代码. 能力有限,尝试改源码滚动的时候也会报错。动态增加flutter创建出来的元素(append1替换成append2方法)是没问题的。

js代码:

    const container = document.createElement('div');
    // 必须指定渲染容器节点滚动方向的尺寸(height).
    container.style.height = '100vh';
    const outter = document.createElement('k-demo-element2');
    container.appendChild(outter);
    const ele = document.createElement('div');
    ele.style.height = '100';
    const clickUi = document.createTextNode(`测试点击`);
    ele.appendChild(clickUi);
    container.appendChild(ele);

    ele.addEventListener('click', function() {
      const tmpdiv = document.createElement('div');
      tmpdiv.style.height = '200px';
      tmpdiv.style.width = '100px';
      tmpdiv.appendChild(document.createTextNode(`第 1个元素`));
      outter.appendChild(tmpdiv);
      // outter.sayHi(tmpdiv); // flutter: Kraken: Hi!
    });
    document.body.appendChild(container);

dart代码:

import 'package:kraken/widget.dart'; import 'package:flutter/material.dart';

class DemoElement2 extends WidgetElement { List goodsList = []; late Widget targetW; bool isInit = false;

// DemoElement2(context) : super(context, defaultStyle: {'display': 'block'}); DemoElement2(context) : super(context);

append1(children) { goodsList[0].appendW(children); }

append2() { goodsList[0].appendW([Container( height: 100, width: 111, child: Text("1111"),)]); }

@override Widget build(BuildContext context, Map<String, dynamic> properties, List children) { // setAttribute("id", "test1"); if (children.length > 0) { append1(children); // TODO append2是没问题的。 // append2() } if (isInit) { return targetW; } isInit = true; goodsList.add(MyList()); targetW = Container( color: Colors.blue, width: 300, height: 500, child:CustomScrollView( slivers: goodsList,)); return targetW; }

dynamic sayHi(List args) { print(args); print(args[0]); print(args[0].runtimeType); }

@override getBindingProperty(String key) { if (key == 'sayHi') { return sayHi; }

return super.getBindingProperty(key);

} } class MyList extends StatefulWidget {

List wList = []; _MyListState state = _MyListState(); @override State createState() { return state; }

appendW(List w) { for (Widget w in wList) { KrakenElementToWidgetAdaptor renderObjectWidget = w as KrakenElementToWidgetAdaptor; // renderObjectWidget.check1(); // TODO 尝试在KrakenElementToWidgetAdaptor增加check1方法,调用detachRenderObject,并且相关的super.mount 和 super.unmount 加上try catch ,能解决每次add元素的child.parend != null // void check1() { // bool isRendererAttached = _krakenNode.isRendererAttached; // print(' isRendererAttached: ${isRendererAttached}'); // // print('zjt isConnected: ${_krakenNode.isConnected}'); // if (isRendererAttached) { // _krakenNode.flutterElement?.detachRenderObject(); // } // } } wList.addAll(w); state.setState(() {

});

} } class MyListState extends State { @override Widget build(BuildContext context) { return SliverList( delegate: SliverChildBuilderDelegate( (, index) => _ListWidget(index), childCount: widget.wList.length, ) ); }

_ListWidget(index) { KrakenElementToWidgetAdaptor renderObjectWidget = widget.wList[index] as KrakenElementToWidgetAdaptor; return Container(child: renderObjectWidget); } }

异常信息:

======== Exception caught by widgets library ======================================================= The following assertion was thrown building Container: 'package:flutter/src/foundation/node.dart': Failed assertion: line 128 pos 12: 'child._parent == null': is not true.

Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause. In either case, please report this assertion by filing a bug on GitHub: https://github.com/flutter/flutter/issues/new?template=2_bug.md

The relevant error-causing widget was: Container Container:file:///Users/apple/job/app/lib/nflutter_components/demo_compont/views/demo_component2.dart:107:12 When the exception was thrown, this was the stack:

2 AbstractNode.adoptChild (package:flutter/src/foundation/node.dart:128:12)

3 RenderObject.adoptChild (package:flutter/src/rendering/object.dart:1331:11)

4 ContainerRenderObjectMixin.insert (package:flutter/src/rendering/object.dart:3288:5)

5 RenderLayoutBox.insert (package:kraken/src/rendering/box_model.dart:202:11)

6 KrakenElementToWidgetAdaptor.createRenderObject (package:kraken/src/widget/element_to_widget_adaptor.dart:29:24)

7 RenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5459:28)

8 KrakenElementToFlutterElementAdaptor.mount (package:kraken/src/widget/element_to_widget_adaptor.dart:65:11)

9 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3631:14)

10 Element.updateChild (package:flutter/src/widgets/framework.dart:3380:20)

11 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4613:16)

12 Element.rebuild (package:flutter/src/widgets/framework.dart:4311:5)

13 StatelessElement.update (package:flutter/src/widgets/framework.dart:4669:5)

14 Element.updateChild (package:flutter/src/widgets/framework.dart:3370:15)

15 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6130:14)

16 Element.updateChild (package:flutter/src/widgets/framework.dart:3370:15)

17 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6130:14)

18 Element.updateChild (package:flutter/src/widgets/framework.dart:3370:15)

19 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4613:16)

20 Element.rebuild (package:flutter/src/widgets/framework.dart:4311:5)

21 StatelessElement.update (package:flutter/src/widgets/framework.dart:4669:5)

22 Element.updateChild (package:flutter/src/widgets/framework.dart:3370:15)

23 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4613:16)

24 Element.rebuild (package:flutter/src/widgets/framework.dart:4311:5)

25 ProxyElement.update (package:flutter/src/widgets/framework.dart:4943:5)

26 Element.updateChild (package:flutter/src/widgets/framework.dart:3370:15)

27 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4613:16)

28 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4763:11)

29 Element.rebuild (package:flutter/src/widgets/framework.dart:4311:5)

30 StatefulElement.update (package:flutter/src/widgets/framework.dart:4795:5)

31 Element.updateChild (package:flutter/src/widgets/framework.dart:3370:15)

32 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4613:16)

33 Element.rebuild (package:flutter/src/widgets/framework.dart:4311:5)

34 StatelessElement.update (package:flutter/src/widgets/framework.dart:4669:5)

35 Element.updateChild (package:flutter/src/widgets/framework.dart:3370:15)

36 SliverMultiBoxAdaptorElement.updateChild (package:flutter/src/widgets/sliver.dart:1243:37)

37 SliverMultiBoxAdaptorElement.performRebuild.processElement (package:flutter/src/widgets/sliver.dart:1148:35)

38 Iterable.forEach (dart:core/iterable.dart:279:35)

39 SliverMultiBoxAdaptorElement.performRebuild (package:flutter/src/widgets/sliver.dart:1192:24)

40 SliverMultiBoxAdaptorElement.update (package:flutter/src/widgets/sliver.dart:1126:7)

41 Element.updateChild (package:flutter/src/widgets/framework.dart:3370:15)

42 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4613:16)

43 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4763:11)

44 Element.rebuild (package:flutter/src/widgets/framework.dart:4311:5)

45 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2578:33)

46 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:882:21)

47 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:363:5)

48 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1145:15)

49 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1082:9)

50 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:996:5)

54 _invoke (dart:ui/hooks.dart:150:10)

55 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:270:5)

56 _drawFrame (dart:ui/hooks.dart:114:31)

(elided 5 frames from class _AssertionError and dart:async)

answershuto commented 2 years ago

是在最新的 main 上测试的吗?这个问题看起来最近修过,由于重复调用 insert 的缘故。

zjt123 commented 2 years ago

是在最新的 main 上测试的吗?这个问题看起来最近修过,由于重复调用 insert 的缘故。

对的 最新的main测试的, commitid :193b7459d38daa997eea9dfb8bfae320787c5326

zjt123 commented 2 years ago

是在最新的 main 上测试的吗?这个问题看起来最近修过,由于重复调用 insert 的缘故。

有相关的北海交流群吗?方便发一下吗?

answershuto commented 2 years ago

答疑只走 issue,群内不答疑。交流群可以在 TSC 那边找到。