当前位置:   article > 正文

Taro使用 微信小程序 副文本编辑器_taro vue 富文本编辑

taro vue 富文本编辑

在这里插入图片描述

一、 引入 小程序富文本编辑器

Taro把一些小程序的原生组件给抽成了插件包括但不限于: editor/page-container,所以直接在代码中写的话是不会被渲染出来的,得经过下面的操作才可以。

二、文件列表

  • HgEditor.vue
  • HgEditor.less
  • iconfont.less
  • editorField.vue // 单独封装的富文本表单组件
  • addGoods.vue // 使用组件的页面文件

1. HgEditor.vue

<template>
	<view class="editor-box">
		<view
			v-if="showTabBar"
			class="editor-box-header"
		>
			<view
				class="operate-box"
				@tap="_addImage"
			>
				<text class="iconfont icon-image" />
			</view>
			<view
				class="operate-box"
				@tap="_format('italic')"
			>
				<text class="iconfont icon-italic" />
			</view>
			<view
				class="operate-box"
				@tap="_format('bold')"
			>
				<text class="iconfont icon-bold" />
			</view>
			<view
				class="operate-box"
				@tap="_format('header', 'h1')"
			>
				<text class="iconfont icon-h1" />
			</view>
			<view
				class="operate-box"
				@tap="_format('header', 'h2')"
			>
				<text class="iconfont icon-h2" />
			</view>
			<view
				class="operate-box"
				@tap="_format('header', 'h3')"
			>
				<text class="iconfont icon-h3" />
			</view>
			<view
				class="operate-box"
				@tap="_format('align', 'left')"
			>
				<text class="iconfont icon-alignLeft" />
			</view>
			<view
				class="operate-box"
				@tap="_format('align', 'right')"
			>
				<text class="iconfont icon-alignRight" />
			</view>
			<view
				class="operate-box"
				@tap="_format('list', 'ordered')"
			>
				<text class="iconfont icon-orderedList" />
			</view>
			<view
				class="operate-box"
				@tap="_format('list', 'bullet')"
			>
				<text class="iconfont icon-unorderedList" />
			</view>
			<view
				class="operate-box"
				@tap="_undo"
			>
				<text class="iconfont icon-undo" />
			</view>
		</view>
		<view class="editor-box-content">
			<Editor
				id="editor"
				class="fz-28 editor"
				:name="name"
				:value="editorValue"
				:placeholder="placeholder"
				:showImgResize="true"
				:show-img-toolbar="true"
				:show-img-resize="true"
				@Blur="blur"
				@Ready="_onEditorReady"
				@Input="_onInputting"
			/>
		</view>
	</view>
</template>
<script>
import Taro from '@tarojs/taro';
import { Editor } from '@tarojs/components';
import request from '@/apis/public';
import './HgEditor.less';
export default {
	name: 'HgEditor',
	components: { Editor },
	props: {
		/** 是否显示工具栏 */
		showTabBar: {
			type: Boolean,
			value: true
		},
		placeholder: {
			type: String,
			value: '请输入图文详情'
		},
		name: {
			type: String,
			value: ''
		},
		editorValue: {
			type: String,
			value: ''
		}
	},
	data () {
		return {
			editorCtx: null
		};
	},
	methods: {
		blur () {
			this.editorCtx.blur();
		},
		_onEditorReady () {
			Taro.createSelectorQuery().select('#editor').context(res => {
				this.editorCtx = res.context;
				const that = this;
				setTimeout(() => {
					if (that.editorValue) {
						res.context.setContents({
							html: that.editorValue
						});
					} else {
						res.context.setContents({
							html: ''
						});
					}
					that.editorCtx.blur();
					Taro.pageScrollTo({
						scrollTop: 0,
						duration: 0
					});
				}, 100);
			}).exec();
		},
		// 插入图片
		_addImage (event) {
			Taro.chooseImage({
				count: 1,
				sizeType: ['compressed'],
				sourceType: ['album'],
				success: (res) => {
					Taro.showLoading({
						title: '上传中',
						mask: true
					});
					this._uploadImage(res.tempFilePaths[0]);
				}
			});
		},
		_uploadImage (tempFilePath) {
			request.uploadFileCommon('/common/img', tempFilePath, 'imgs', this.wxToken)
				.then(res => {
					if (res.result_code === 1) {
						this.editorCtx.insertImage({
							src: res.data[0]
						});
					} else {
						Taro.showToast({
							icon: 'error',
							title: '上传失败',
							mask: true
						});
					}
					Taro.hideLoading();
				})
				.catch(e => {
					Taro.showToast({
						title: '上传失败',
						icon: 'none',
						duration: 1000 // 持续的时间
					});
					Taro.hideLoading();
				});
		},
		_format (type, val) {
			this.editorCtx.format(type, val);
		},
		// 撤销
		_undo () {
			this.editorCtx.undo();
		},
		// 监控输入
		_onInputting (e) {
			const html = e.detail.html;
			// const text = e.detail.text;
			this.$emit('input', html);
		}
	}
};
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204

2. HgEditor.less

/* components/hg-editor/hg-editor.wxss */
@import "./iconfont.less";

.editor-box {
	width: 100%;
	padding: 0;
	box-sizing: border-box;
	background-color: #fff;
	background: #F7F7F7;
}

.editor-box-header,
.editor-box-content {
  	width: 100%;
}

.editor-box-header {
	display: flex;
	flex-flow: row nowrap;
	align-items: center;
	justify-content: space-between;
	padding: 20rpx 20rpx;
	box-sizing: border-box;
	border-bottom: 2rpx solid #E6E6E6;
	background-color: #F6F6F6;
}

.editor-box-header>.operate-box {
	width: 40rpx;
	height: 40rpx;
	overflow: hidden;
	color: gray;
}

.editor-box-content {
	padding: 20rpx;
	box-sizing: border-box;
	background: #F7F7F7;
	.editor {
		height: auto;
		margin-top: 0;
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

3. iconfont.less

@font-face {
  font-family: 'iconfont';  /* Project id 2549449 */
  src: url('//at.alicdn.com/t/font_2549449_hxmflg4qsr6.woff2?t=1621002720450') format('woff2'),
       url('//at.alicdn.com/t/font_2549449_hxmflg4qsr6.woff?t=1621002720450') format('woff'),
       url('//at.alicdn.com/t/font_2549449_hxmflg4qsr6.ttf?t=1621002720450') format('truetype');
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 38rpx;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-undo:before {
  content: "\e609";
}

.icon-hr:before {
  content: "\e60a";
}

.icon-h3:before {
  content: "\e60b";
}

.icon-quote:before {
  content: "\e60c";
}

.icon-bold:before {
  content: "\e60e";
}

.icon-orderedList:before {
  content: "\e612";
}

.icon-h2:before {
  content: "\e61a";
}

.icon-italic:before {
  content: "\e61c";
}

.icon-unorderedList:before {
  content: "\e620";
}

.icon-alignLeft:before {
  content: "\e621";
}

.icon-alignRight:before {
  content: "\e622";
}

.icon-h1:before {
  content: "\e623";
}

.icon-image:before {
  content: "\e629";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

4. editorField.vue

<template>
	<view class="form-item  no-border">
		<text class="label">
			{{ label }}
		</text>
		<view class="ql-container">
			<HgEditor
				ref="hgEditor"
				:showTabBar="true"
				:editorValue="value"
				:placeholder="placeholder"
				:name="prop"
				@input="handleInput"
			/>
		</view>
	</view>
</template>
<script>
import HgEditor from '../HgEditor.vue';
import './editorField.less';

export default {
	name: 'EditorField',
	components: { HgEditor },
	props: {
		value: [String, Number],
		prop: String,
		label: String,
		placeholder: String,
		type: {
			type: String,
			default: 'text'
		},
		uploadImageURL: {
			type: String,
			value: ''
		},
		maxlength: {
			type: Number,
			default: 30
		},
		disabled: {
			type: Boolean,
			default: false
		}
	},
	methods: {
		handleInput (content) {
			this.$emit('fieldChange', this.prop, content);
		},
		initEditor () {
			this.$refs.hgEditor._onEditorReady();
		}
	}
};
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

5. editorField.less


.form-item {
	position: relative;
	min-height: 167rpx;
    padding-top: 60rpx;
    padding-bottom: 23rpx;
    box-sizing: border-box;
    border-bottom: 1rpx solid #F0F0F0;
	&.no-border {
		border: none !important;
	}
	.label {
		font-size: 30rpx;
		font-family: PingFangSC-Medium;
		font-weight: 500;
		color: #333333;
	}
	.sub-label {
		margin-left: 10rpx;
		font-size: 22rpx;
		font-family: PingFang SC;
		font-weight: 400;
		color: #CCCCCC;
	}
	.input-text {
		margin-top: 28rpx;
		font-size: 28rpx;
	}
	.textarea {
		width: 100%;
		height: 286px;
		margin-top: 34rpx;
		padding: 35rpx 30rpx;
		box-sizing: border-box;
		font-size: 28rpx;
		background: #F5F6F8;
		border-radius: 20rpx;
	}
	.counter {
		position: absolute;
		bottom: 30rpx;
		right: 35rpx;
		font-size: 22rpx;
		font-family: PingFang SC;
		font-weight: 400;
		color: #CCCCCC;
	}
	.placeholder-class {
		font-size: 28rpx;
		font-family: PingFangSC-Regular;
		font-weight: 400;
		color: #CCCCCC;
	}
	.picker {
		position: relative;
		.arrow {
			width: 15rpx;
			height: 26rpx;
			position: absolute;
			right: 0;
			bottom: 14rpx;
		}
	}
	.upload-container {
		margin-top: 30rpx;
		flex-wrap: wrap;
		.ui_uploader_item {
			position: relative;
			width: 196rpx;
			height: 196rpx;
			margin-right: 20rpx;
			margin-bottom: 20rpx;
			border-radius: 10rpx;
			.ui_uploader_item_icon {
				position: absolute;
				right: -20rpx;
				top: -20rpx;
				background: #fff;
				border-radius: 50%;
			}
			image {
				width: 196rpx;
				height: 196rpx;
			}
		}
		.ui_uploader {
			position: relative;
			margin: 20rpx 0;
			margin-top: 0;
			margin-right: 20rpx;
			width: 196rpx;
			height: 196rpx;
			box-sizing: border-box;
			background: #F7F7F7;
			border-radius: 10rpx;
			image {
				width: 57rpx;
				height: 57rpx;
			}
		}
	}
	.ql-container {
		height: auto;
		margin-top: 34rpx;
		border-radius: 20rpx;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107

6. addGoods.vue

<template>
	<EditorField
		ref="editorField"
		:value="formData.content"
		prop="content"
		label="商品详情"
		placeholder="请输入商品详情"
		@fieldChange="fieldChangeHandle"
	/>
</template>
<script>
	export default {
		data () {
			return {
				formData: {
					id: '',
					content: ''
				}
			};
		},
		methods: {
			fieldChangeHandle (field, val) {
				this.formData[field] = val;
			}
		}
	}
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/91155
推荐阅读