博文的Flutter版本
Flutter 1.17.0 • channel beta • https://github.com/flutter/flutter.git
Framework • revision d3ed9ec945 (6 天前) • 2020-04-06 14:07:34 -0700
Engine • revision c9506cb8e9
Tools • Dart 2.8.0 (build 2.8.0-dev.18.0 eea9717938)
CodeMirror 是一款“Online Source Editor”,基于Javascript,短小精悍,实时在线代码高亮显示,他不是某个富文本编辑器的附属产品,他是许多大名鼎鼎的在线代码编辑器的基础库。
codemirror
目前只有Google团队推出的dart web
项目,但是未在flutter web
中实现
我们知道,在flutter_web
中使用原生html
插件,需要使用HtmlElementView
组件支持,并在initState
中注册组件并配置组件…以下是痛苦的踩坑之路
code-mirror
的html IDDivElement
,用于存放CodeMirror
,处理回调HtmlElementView
,UIoptions
,codemirror
的配置 // UI变量
String _codemirrorId = "code-edit";
html.DivElement _codeContent = html.DivElement();
CodeMirror _codeMirror;
HtmlElementView _codeView;
Map options = {'mode': 'clike', 'theme': 'monokai'};
initState
中注册并生成HtmlElementView
注意1:这里的
ui
是dart:ui
import 'dart:ui' as ui;
注意2:
// ignore: undefined_prefixed_name
用于忽略registerViewFactory
未定义问题
@override
void initState() {
super.initState();
// 注册codemirror标签
// ignore: undefined_prefixed_name
ui.platformViewRegistry
.registerViewFactory(_codemirrorId, (int viewId) => _codeContent);
_codeView = HtmlElementView(
viewType: _codemirrorId,
);
}
build
方法中放入_codeView
注意:一定要设置
Container
的宽高,否则出现白屏
body: Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
FlatButton(onPressed: showCodeEditor, child: Text("show")),
Container(
decoration: BoxDecoration(color: Colors.grey),
width: 400,
height: 400,
>>>>>>>>>> child: _codeView, <<<<<<<<<<<<<<<<<<<<<<<<<<<<
),
],
),
),
_codeView
中导入CodeMirror
注意:_codeView
在对应的html中,使用了shadowRoot
进行隔离,在index.html
的header
中添加CSS、JS是无效的,无法作用在shadowRoot
内部,所以我们要另辟蹊径!
目前有两种方案:
使用iFrame element
导入一个完整的html
页面,然后通过访问iFrame
的contentDocument
变量的querySelector
方法拿到html body
里我们定义好的一个空div
,然后使用codemirror.fromElement
方法填充进去
❎不行,因为Dart SDK 2.8.0
还没有将contentDocument
开放出来…GitHub Issue链接给出的解决方案是转化为JsObject
,但是这样就没法使用codemirror
的构造函数进行构造了,而且JsObject
生涩难用,成本实在太高
直接在shadowRoot
中配置!(以下操作为该步骤)
shadowRoot
注意!_codeView的shadowRoot
没法通过codeView.shadowRoot
方法(无此方法)!只能通过DOM数查找,所有的HtmlView
在DOM树种都是flt-platform-view,开发时如果有多个,这个下标注意更换为对应数字
var node = html.document.getElementsByTagName("flt-platform-view")[0] as html.HtmlElement;
如果找不到
fit-platform-view
,请加入Future.delayed
方法,延迟一段时间
DivElement
中实例化codemirror
_codeMirror = CodeMirror.fromElement(_codeContent, options: options);
这里使用
cdn.bootcss.com
的CSS和JS文件
注意innerHTML
和OuterHtml
的区别,我们要使用的是setInnerHtml
方法。注意:需要传入一个支持tag
和attributes
的验证器,否则header无法添加
var headElement = html.HeadElement();
// node 验证器
final NodeValidatorBuilder _htmlValidator=new NodeValidatorBuilder.common()
..allowElement('link',attributes: ["rel","href"])
..allowElement('script',attributes: ["src"]);
// 设置header
headElement.setInnerHtml('',validator: _htmlValidator);
shadowRoot
的children
内node.shadowRoot.children.insert(0, headElement);
至此,如果配置正确,将成功实现codemirror
嵌入flutter_web
了,效果如下
但是仍然有些问题!空格
和Tab
按键会和Flutter
有些许冲突,这个之后日益完善吧~