携手创作,共同生长!这是我参与「日新计划 8 月更文应战」的第13天,点击查看活动概况
导言
- 富文本编辑器的应用场景: 编辑产品概况
预览:
- 规划思路: 编辑器基于WKWebview完成,Editor运用WKWebview加载一个本地editor.html文件,Editor运用
evaluateJavaScript
履行JS往本地html增加标签代码,编辑器最终输出富文本字符串(html代码)传输给服务器。
"remark":"<p>产品概况看看</p>\n<p style=\"text-align: right;\">jjjj<img src=\"http://bug.xxx.com:7000/zentao/file-read-6605.png\" alt=\"dddd\" width=\"750\" height=\"4052\" /></p>\n<p style=\"text-align: right;\"> </p>\n<p style=\"text-align: right;\"> </p>\n<p style=\"text-align: right;\"> </p>\n<p style=\"text-align: right;\"> </p>\n<p style=\"text-align: right;\"> </p>\n<p style=\"text-align: right;\"> </p>\n<p style=\"text-align: right;\"><img src=\"http://bug.xxx.com:7000/zentao/file-read-6605.png\" alt=\"\" width=\"750\" height=\"4052\" /></p>"
-
运用IQKeyboardManager 键盘管理工具,布局采用Masonry,MVVM数据绑定。
-
界面规划:推荐把工具栏增加到键盘,或者放在富文本编辑器的顶部
I 上篇: 核心代码逻辑
blog.csdn.net/z929118967/…
II 工具栏规划(含demo)
2.1 工具栏在富文本编辑器的底部
demo: download.csdn.net/download/u0…
2.2 工具栏在富文本编辑器的顶部
demo地址:download.csdn.net/download/u0…
-(WKWebView *)editorView{
if (!_editorView) {
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc]init];
WKUserContentController *userCon = [[WKUserContentController alloc]init];
config.userContentController = userCon;
WKWebView *tmp = [[WKWebView alloc]initWithFrame:CGRectZero configuration:config];
//223
// [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, pDeviceWidth, self.view.frame.size.height-KWEditorBar_Height) configuration:config];
_editorView = tmp;
// [userCon addScriptMessageHandler:self name:@"column"];
tmp.navigationDelegate = self;
tmp.hidesInputAccessoryView = YES;// 去掉键盘自带的工具条
tmp.scrollView.bounces = NO;
tmp.backgroundColor = [UIColor whiteColor];
// anObserver:观察者目标,这个目标必须完成observeValueForKeyPath:ofObject:change:context:办法,以响应特点的修正告诉。
// keyPath:被监听的特点。这个值不能为nil。
// options:监听选项,这个值可以是NSKeyValueObservingOptions选项的组合。关于监听选项,咱们会在下面介绍。
// context:恣意的额定数据,咱们可以将这些数据作为上下文数据,它会传递给观察者目标的observeValueForKeyPath:ofObject:change:context:办法。这个参数的意义在于用于区分同一目标监听同一特点(从属于同一目标)的多个不同的监听。咱们将在下面看到。
//
[tmp addObserver:self forKeyPath:@"URL" options:NSKeyValueObservingOptionNew context:nil];
[self addSubview:tmp];
__weak __typeof__(self) weakSelf = self;
[tmp mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.offset(0);//test
make.height.mas_equalTo(kAdjustRatio(223));
// make.top.offset(0);
make.left.right.offset(0);
make.top.equalTo(weakSelf.toolBarView.mas_bottom).offset(0);
}];
[self initConfig];
}
return _editorView;
}
- (KNEditorBar *)toolBarView{
if (!_toolBarView) {
KNEditorBar *tmp = [KNEditorBar editorBar];
_toolBarView = tmp;
tmp.frame = CGRectMake(0,self.frame.size.height - KWEditorBar_Height, self.frame.size.width, KWEditorBar_Height);
tmp.backgroundColor = rgb(237, 237, 237);
[self addSubview:tmp];
__weak __typeof__(self) weakSelf = self;
[tmp mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.offset(0);
make.height.mas_equalTo(KWEditorBar_Height);
// make.top.equalTo(weakSelf.editorView.mas_bottom).offset(0);
make.top.offset(KWFontBar_Height-13);
// make.bottom.offset(0);
}];
tmp.delegate = self;
[tmp addObserver:self forKeyPath:@"transform" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
self.editorView.associatedObject = tmp;
}
return _toolBarView;
}
- (KNFontStyleBar *)fontBar{
if (!_fontBar) {
_fontBar = [[KNFontStyleBar alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(self.toolBarView.frame) - KWFontBar_Height - KWEditorBar_Height, self.frame.size.width, KWFontBar_Height)];
_fontBar.delegate = self;
[_fontBar.heading2Item setSelected:YES];
}
return _fontBar;
}
#pragma mark -editorbarDelegate,告诉外围html有变化
- (void)editorBar:(KNEditorBar *)editorBar didClickIndex:(k_RichToolBarButtonIndex)buttonIndex{
switch (buttonIndex) {
case k_RichToolBarButtonIndex4KeyboardButton:{//键盘唤醒与躲藏
NSLog(@"%f",self.toolBarView.transform.ty);
// if (self.toolBarView.transform.ty < 0) {
if (self.models.isVisable) {
[self.editorView hiddenKeyboard];
// self.toolBarView.keyboardButton.selected = NO;
}else{
[self.editorView focusTextEditor];
self.toolBarView.keyboardButton.selected = YES;
}
}
break;
case k_RichToolBarButtonIndex4undoButton:{//后退
[self.editorView undo];
}
break;
case k_RichToolBarButtonIndex4redoButton:{//前进
[self.editorView redo];
}
break;
case k_RichToolBarButtonIndex4fontButton:{//字体
editorBar.fontButton.selected = !editorBar.fontButton.selected;
if (editorBar.fontButton.selected) {
[self addSubview:self.fontBar];
__weak __typeof__(self) weakSelf = self;
[self.fontBar mas_updateConstraints:^(MASConstraintMaker *make) {
// _fontBar = [[KNFontStyleBar alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(self.toolBarView.frame) - KWFontBar_Height - KWEditorBar_Height, self.frame.size.width, KWFontBar_Height)];
make.bottom.equalTo(weakSelf.toolBarView.mas_top);
make.left.right.offset(0);
// make.width.offset(0);
make.height.mas_equalTo( KWFontBar_Height);
}];
}else{
[self.fontBar removeFromSuperview];
}
}
break;
case k_RichToolBarButtonIndex4linkButton:{//超衔接
[self insertLink];
}
break;
case k_RichToolBarButtonIndex4imageButton:{//图片
[self insertImage];
}
break;
default:
break;
}
}
III 常见问题
3.1 躲藏键盘失掉焦点时,图片内容被清空
问题: 标签的占位符,经过监听失掉焦点事情,假如文本trim之后长度为0,就清空div数据,显现占位符。
原因:element.text()
获取的是文本,只判断了文本,而疏忽了img标签。
<div id="zss_editor_content" class="zs_editor_content" contenteditable="true" placeholder="请输入文章正文"></div>
zss_editor.setPlaceholder = function(placeholder) {
var editor = $('#zss_editor_content');
//set placeHolder
editor.attr("placeholder",placeholder);
//set focus
editor.focusout(function(){//当元素失掉焦点时触发 focusout 事情
var element = $(this);
if (!element.text().trim().length) {
element.empty();
}
});
}
处理方法: 修正占位符的判断条件
//element.text() 获取的是文本,只判断了文本,而疏忽了img标签。,所以换成html()判断子标签
// window.alert(element.html());
if (!element.html().trim().length ) {
element.empty();
}
去除换行和空格在判断是否内容为空
var html =element.html().trim();
if (!html.length || html=="<br>") {
element.empty();
}
3.2 刺进图片无效
问题:刺进图片无效 原因: 点击刺进图片按钮时,WebView获取到焦点 处理方法:点击刺进图片按钮时,尝试获取焦点。
#pragma mark - 刺进图片
//https://www.6hu.cc/wp-content/uploads/2023/02/1677160730-3ebe39d5e5c341c.png
-(void)insertImage{
if (!self.models.isVisable) {
[self.editorView focusTextEditor];// 获取焦点
}
[self.editorView prepareInsertImage];
if(self.models.insertImageBlock){
self.models.insertImageBlock(nil);
}
}
#pragma mark - 刺进链接
- (void)insertLink {
if (!self.models.isVisable) {
[self.editorView focusTextEditor];// 获取焦点
}
[self.editorView prepareInsertImage];
if(self.models.showInsertLinkDialogBlockWithLink){
self.models.showInsertLinkDialogBlockWithLink(nil,nil);
}
// [self showInsertLinkDialogWithLink:nil title:nil];
}
3.3 刺进的网络图片 只能增加到最后位置
问题:刺进的网络图片 只能增加到最后位置,不能再中间刺进。
原因: 刺进图片时多次获取焦点,把焦点定位到最后的位置 处理:运用5.2 章节的方法
if (!self.viewModel.model4editor.isVisable) {
// [self.viewModel.model4editor.editorView focusTextEditor];
}
see also
大众号:iOS逆向