613 行
18 KiB
Plaintext
613 行
18 KiB
Plaintext
<template>
|
||
<view class="page-root">
|
||
<view class="preview-panel">
|
||
<view class="preview-header">
|
||
<text class="uni-title-text">editor 属性示例</text>
|
||
</view>
|
||
|
||
<view class="preview-state-row">
|
||
<text class="preview-state-text">read-only: {{ data.readOnly }}</text>
|
||
<!-- #ifndef MP -->
|
||
<text class="preview-state-text">type: {{ getTypeLabel() }}</text>
|
||
<!-- #endif -->
|
||
</view>
|
||
|
||
<view class="preview-state-row">
|
||
<view v-if="showLogs">
|
||
<text class="preview-state-text">X: {{ data.editorX }}</text>
|
||
<text class="preview-state-text">Y: {{ data.editorY }}</text>
|
||
<text class="preview-state-text">width: {{ data.editorWidth }}</text>
|
||
<text class="preview-state-text">height: {{ data.editorHeight }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="preview-editor-box">
|
||
<editor
|
||
v-if="data.showEditor"
|
||
id="editor-props-demo"
|
||
class="preview-editor"
|
||
:read-only="data.readOnly"
|
||
:placeholder="data.appliedPlaceholder"
|
||
:show-img-size="data.appliedShowImgSize"
|
||
:show-img-toolbar="data.appliedShowImgToolbar"
|
||
:show-img-resize="data.appliedShowImgResize"
|
||
:type="data.editorType"
|
||
@ready="onEditorReady"
|
||
@focus="onEditorFocus"
|
||
@blur="onEditorBlur"
|
||
@input="onEditorInput"
|
||
@statuschange="onStatusChange"
|
||
/>
|
||
</view>
|
||
|
||
<view class="preview-toolbar">
|
||
<view class="preview-toolbar-item" @tap="insertSampleText">
|
||
<text class="preview-toolbar-icon iconfont">A</text>
|
||
</view>
|
||
<view class="preview-toolbar-item" @tap="insertSampleImage">
|
||
<text class="preview-toolbar-icon iconfont">{{""}}</text>
|
||
</view>
|
||
<view :class="data.boldActive ? 'preview-toolbar-item preview-toolbar-item-active' : 'preview-toolbar-item'" @tap="toggleBold">
|
||
<text :class="data.boldActive ? 'preview-toolbar-icon preview-toolbar-icon-active iconfont' : 'preview-toolbar-icon iconfont'">{{""}}</text>
|
||
</view>
|
||
<view :class="data.alignCenterActive ? 'preview-toolbar-item preview-toolbar-item-active' : 'preview-toolbar-item'" @tap="setAlignCenter">
|
||
<text :class="data.alignCenterActive ? 'preview-toolbar-icon preview-toolbar-icon-active iconfont' : 'preview-toolbar-icon iconfont'">{{""}}</text>
|
||
</view>
|
||
<view class="preview-toolbar-item" @tap="removeFormat">
|
||
<text class="preview-toolbar-icon iconfont">{{""}}</text>
|
||
</view>
|
||
<view class="preview-toolbar-item" @tap="clearEditor">
|
||
<text class="preview-toolbar-icon iconfont">{{""}}</text>
|
||
</view>
|
||
<view class="preview-toolbar-item" @tap="blurEditor">
|
||
<text class="preview-toolbar-icon iconfont">{{""}}</text>
|
||
</view>
|
||
<!-- #ifndef MP -->
|
||
<view class="preview-toolbar-item" @tap="insertMention">
|
||
<text class="preview-toolbar-icon iconfont">@</text>
|
||
</view>
|
||
<!-- #endif -->
|
||
</view>
|
||
</view>
|
||
|
||
<scroll-view class="props-scroll" direction="vertical">
|
||
<view class="uni-padding-wrap">
|
||
<view class="uni-title uni-common-mt">
|
||
<text class="uni-title-text">可动态修改属性</text>
|
||
</view>
|
||
</view>
|
||
<boolean-data :defaultValue="data.readOnly" title="read-only:设置编辑器为只读,可动态修改" @change="onReadOnlyChange"></boolean-data>
|
||
<!-- #ifndef MP -->
|
||
<enum-data :items="data.typeItems" title="type:null | none,控制聚焦时是否弹出键盘" @change="onTypeChange"></enum-data>
|
||
<!-- #endif -->
|
||
|
||
<view class="uni-padding-wrap">
|
||
<view class="uni-title uni-common-mt">
|
||
<text class="uni-title-text">初始化生效属性</text>
|
||
</view>
|
||
<text class="uni-subtitle-text">placeholder 与 show-img-* 调整后不会直接作用到当前 editor,请点击下方按钮重建后查看。</text>
|
||
</view>
|
||
<input-data :defaultValue="data.draftPlaceholder" title="placeholder:提示信息,不可动态修改" type="text" @confirm="onPlaceholderChange"></input-data>
|
||
<boolean-data :defaultValue="data.draftShowImgSize" title="show-img-size:点击图片时显示图片大小控件,不可动态修改" @change="onDraftShowImgSizeChange"></boolean-data>
|
||
<boolean-data :defaultValue="data.draftShowImgToolbar" title="show-img-toolbar:点击图片时显示工具栏控件,不可动态修改" @change="onDraftShowImgToolbarChange"></boolean-data>
|
||
<boolean-data :defaultValue="data.draftShowImgResize" title="show-img-resize:点击图片时显示修改尺寸控件,不可动态修改" @change="onDraftShowImgResizeChange"></boolean-data>
|
||
|
||
<view class="uni-padding-wrap uni-common-mt">
|
||
<view class="uni-title">
|
||
<text class="uni-title-text">当前应用中的 editor 配置</text>
|
||
</view>
|
||
<text class="uni-subtitle-text">placeholder:{{ data.appliedPlaceholder }}</text>
|
||
<text class="uni-subtitle-text">show-img-size:{{ data.appliedShowImgSize }}</text>
|
||
<text class="uni-subtitle-text">show-img-toolbar:{{ data.appliedShowImgToolbar }}</text>
|
||
<text class="uni-subtitle-text">show-img-resize:{{ data.appliedShowImgResize }}</text>
|
||
<button type="primary" size="mini" class="action-button apply-button" @tap="rebuildEditor">重建 editor 并应用初始化属性</button>
|
||
</view>
|
||
|
||
<view v-if="showLogs" class="uni-padding-wrap uni-common-mt">
|
||
<view class="uni-title">
|
||
<text class="uni-title-text">事件示例</text>
|
||
</view>
|
||
<text class="uni-subtitle-text">@ready:{{ data.readyCount }}</text>
|
||
<text class="uni-subtitle-text">@focus:{{ data.focusCount }}</text>
|
||
<text class="uni-subtitle-text">@blur:{{ data.blurCount }}</text>
|
||
<text class="uni-subtitle-text">@input:{{ data.inputCount }}</text>
|
||
<text class="uni-subtitle-text">@statuschange:{{ data.statusChangeCount }}</text>
|
||
<text class="uni-subtitle-text">最近状态:{{ data.statusSummary }}</text>
|
||
</view>
|
||
|
||
<view v-if="showLogs" class="uni-padding-wrap uni-common-mt uni-common-mb">
|
||
<view class="uni-title event-header-row">
|
||
<text class="uni-title-text">事件日志</text>
|
||
<button size="mini" @tap="clearLogs">清空日志</button>
|
||
</view>
|
||
<view class="log-box" v-if="data.logs.length > 0">
|
||
<text v-for="(item, index) in data.logs" :key="index" class="log-text">{{ item }}</text>
|
||
</view>
|
||
<text v-else class="uni-subtitle-text">等待事件触发...</text>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<navigator style="margin-top: 20px;" url="./editor-edit">
|
||
<button>富文本编辑模板</button>
|
||
</navigator>
|
||
|
||
<bottom-safe-area />
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="uts">
|
||
import { ItemType } from '@/components/enum-data/enum-data-types'
|
||
|
||
type EditorPropsPageData = {
|
||
showEditor: boolean
|
||
readOnly: boolean
|
||
editorType: string | null
|
||
draftPlaceholder: string
|
||
appliedPlaceholder: string
|
||
draftShowImgSize: boolean
|
||
appliedShowImgSize: boolean
|
||
draftShowImgToolbar: boolean
|
||
appliedShowImgToolbar: boolean
|
||
draftShowImgResize: boolean
|
||
appliedShowImgResize: boolean
|
||
editorCtx: EditorContext | null
|
||
readyCount: number
|
||
focusCount: number
|
||
blurCount: number
|
||
inputCount: number
|
||
statusChangeCount: number
|
||
boldActive: boolean
|
||
alignCenterActive: boolean
|
||
statusSummary: string
|
||
logs: string[]
|
||
typeItems: ItemType[]
|
||
editorX: number
|
||
editorY: number
|
||
editorWidth: number
|
||
editorHeight: number
|
||
insertImageWidth: number
|
||
insertImageHeight: number
|
||
}
|
||
|
||
const SAMPLE_TEXT = '这是 editor 示例文本。你可以继续输入内容,也可以滚动下方属性区实时调整 editor 状态。'
|
||
function createTypeItems(selectedValue: number): ItemType[] {
|
||
return [
|
||
{ value: 0, name: 'null:聚焦弹出键盘', checked: selectedValue == 0 },
|
||
{ value: 1, name: 'none:聚焦不弹出键盘', checked: selectedValue == 1 }
|
||
]
|
||
}
|
||
|
||
const showLogs = false
|
||
|
||
const initialData: EditorPropsPageData = {
|
||
showEditor: true,
|
||
readOnly: false,
|
||
editorType: null,
|
||
draftPlaceholder: '请输入内容,placeholder 仅初始化生效',
|
||
appliedPlaceholder: '请输入内容,placeholder 仅初始化生效',
|
||
draftShowImgSize: true,
|
||
appliedShowImgSize: true,
|
||
draftShowImgToolbar: true,
|
||
appliedShowImgToolbar: true,
|
||
draftShowImgResize: true,
|
||
appliedShowImgResize: true,
|
||
editorCtx: null,
|
||
readyCount: 0,
|
||
focusCount: 0,
|
||
blurCount: 0,
|
||
inputCount: 0,
|
||
statusChangeCount: 0,
|
||
boldActive: false,
|
||
alignCenterActive: false,
|
||
statusSummary: '等待 @statuschange',
|
||
logs: [],
|
||
typeItems: createTypeItems(0),
|
||
editorX: 0,
|
||
editorY: 0,
|
||
editorWidth: 0,
|
||
editorHeight: 0,
|
||
insertImageWidth: 0,
|
||
insertImageHeight: 0
|
||
}
|
||
|
||
const data = reactive<EditorPropsPageData>(initialData)
|
||
|
||
function appendLog(tag: string, detail: string) {
|
||
const entry = `${new Date().toLocaleTimeString()} [${tag}] ${detail}`
|
||
data.logs.unshift(entry)
|
||
if (data.logs.length > 12) {
|
||
data.logs.pop()
|
||
}
|
||
}
|
||
|
||
function getTypeLabel(): string {
|
||
return data.editorType == 'none' ? 'none(聚焦不弹键盘)' : 'null(聚焦弹键盘)'
|
||
}
|
||
|
||
function summarizeText(text: string): string {
|
||
if (text.length <= 24) {
|
||
return text
|
||
}
|
||
return `${text.substring(0, 24)}...`
|
||
}
|
||
|
||
function syncTypeItems() {
|
||
const selectedValue = data.editorType == 'none' ? 1 : 0
|
||
data.typeItems = createTypeItems(selectedValue)
|
||
}
|
||
|
||
function onReadOnlyChange(checked: boolean) {
|
||
data.readOnly = checked
|
||
appendLog('prop', `read-only => ${checked}`)
|
||
}
|
||
|
||
function onTypeChange(value: number) {
|
||
data.editorType = value == 1 ? 'none' : null
|
||
syncTypeItems()
|
||
appendLog('prop', `type => ${data.editorType == null ? 'null' : data.editorType}`)
|
||
}
|
||
|
||
function onPlaceholderChange(value: string) {
|
||
data.draftPlaceholder = value
|
||
appendLog('draft', `placeholder 待应用 => ${data.draftPlaceholder}`)
|
||
}
|
||
|
||
function onDraftShowImgSizeChange(checked: boolean) {
|
||
data.draftShowImgSize = checked
|
||
appendLog('draft', `show-img-size 待应用 => ${checked}`)
|
||
}
|
||
|
||
function onDraftShowImgToolbarChange(checked: boolean) {
|
||
data.draftShowImgToolbar = checked
|
||
appendLog('draft', `show-img-toolbar 待应用 => ${checked}`)
|
||
}
|
||
|
||
function onDraftShowImgResizeChange(checked: boolean) {
|
||
data.draftShowImgResize = checked
|
||
appendLog('draft', `show-img-resize 待应用 => ${checked}`)
|
||
}
|
||
|
||
function rebuildEditor() {
|
||
data.appliedPlaceholder = data.draftPlaceholder
|
||
data.appliedShowImgSize = data.draftShowImgSize
|
||
data.appliedShowImgToolbar = data.draftShowImgToolbar
|
||
data.appliedShowImgResize = data.draftShowImgResize
|
||
data.editorCtx = null
|
||
data.boldActive = false
|
||
data.alignCenterActive = false
|
||
data.statusSummary = '等待 @statuschange'
|
||
data.showEditor = false
|
||
setTimeout(() => {
|
||
data.showEditor = true
|
||
}, 0)
|
||
appendLog('rebuild', '已重建 editor,初始化属性已重新应用')
|
||
}
|
||
|
||
function updateEditorRect() {
|
||
// #ifndef MP
|
||
const editorElement = uni.getElementById('editor-props-demo')
|
||
const editorRect = editorElement?.getBoundingClientRect()
|
||
if (editorRect != null) {
|
||
data.editorX = editorRect.x
|
||
data.editorY = editorRect.y
|
||
data.editorWidth = editorRect.width
|
||
data.editorHeight = editorRect.height
|
||
// #ifdef APP-IOS || APP-HARMONY || APP-ANDROID
|
||
const systemInfo = uni.getSystemInfoSync()
|
||
data.editorY += systemInfo.safeAreaInsets.top + 44
|
||
// #endif
|
||
}
|
||
// #endif
|
||
// #ifdef MP
|
||
wx.createSelectorQuery().select('#editor-props-demo').boundingClientRect(function(editorRect){
|
||
data.editorX = editorRect.top
|
||
data.editorY = editorRect.left
|
||
data.editorWidth = editorRect.width
|
||
data.editorHeight = editorRect.height
|
||
|
||
const windowInfo = uni.getWindowInfo()
|
||
data.editorY += windowInfo.safeAreaInsets.top + 44
|
||
}).exec()
|
||
// #endif
|
||
}
|
||
|
||
function onEditorReady() {
|
||
const options: CreateEditorContextAsyncOptions = {
|
||
id: 'editor-props-demo',
|
||
success: (context: EditorContext) => {
|
||
data.editorCtx = context
|
||
data.readyCount += 1
|
||
updateEditorRect()
|
||
appendLog('ready', '编辑器初始化完成')
|
||
},
|
||
fail: (error: UniError) => {
|
||
appendLog('error', `createEditorContextAsync fail: ${error.errMsg}`)
|
||
}
|
||
}
|
||
uni.createEditorContextAsync(options)
|
||
}
|
||
|
||
function onEditorFocus(event: UniEditorFocusEvent) {
|
||
data.focusCount += 1
|
||
appendLog('focus', `text=${summarizeText(event.detail.text)}`)
|
||
}
|
||
|
||
function onEditorBlur(event: UniEditorBlurEvent) {
|
||
data.blurCount += 1
|
||
appendLog('blur', `text=${summarizeText(event.detail.text)}`)
|
||
}
|
||
|
||
function onEditorInput(event: UniEditorInputEvent) {
|
||
data.inputCount += 1
|
||
appendLog('input', `text=${summarizeText(event.detail.text)}`)
|
||
}
|
||
|
||
function onStatusChange(event: UniEditorStatusChangeEvent) {
|
||
data.statusChangeCount += 1
|
||
data.boldActive = event.detail.bold == true
|
||
data.alignCenterActive = event.detail.align == 'center'
|
||
const align = event.detail.align != null ? event.detail.align : 'default'
|
||
const fontSize = event.detail.fontSize != null ? event.detail.fontSize : 'default'
|
||
data.statusSummary = `bold=${event.detail.bold == true}, align=${align}, fontSize=${fontSize}`
|
||
appendLog('statuschange', data.statusSummary)
|
||
}
|
||
|
||
function insertSampleText() {
|
||
data.editorCtx?.insertText({
|
||
text: SAMPLE_TEXT,
|
||
success: () => {
|
||
appendLog('action', '已插入示例文本')
|
||
}
|
||
})
|
||
}
|
||
|
||
const src = 'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/uni-app.png'
|
||
function insertImage() {
|
||
data.editorCtx?.insertImage({
|
||
src,
|
||
alt: '示例图片',
|
||
success: () => {
|
||
appendLog('action', '已插入示例图片,请点击图片验证 show-img-*')
|
||
},
|
||
fail: () => {
|
||
appendLog('error', '插入示例图片失败')
|
||
}
|
||
})
|
||
}
|
||
function insertSampleImage() {
|
||
uni.getImageInfo({
|
||
src,
|
||
success(res) {
|
||
console.log('res: ',res);
|
||
data.insertImageWidth = res.width
|
||
data.insertImageHeight = res.height
|
||
appendLog('network', `图片加载成功: ${summarizeText(src)}`)
|
||
insertImage()
|
||
},
|
||
fail() {
|
||
insertImage()
|
||
}
|
||
})
|
||
}
|
||
|
||
const insertMention = () => {
|
||
data.editorCtx?.insertMention({
|
||
id: '000',
|
||
name: 'uni-app x',
|
||
success: (res: any) => {
|
||
console.log('insert mention success')
|
||
}
|
||
})
|
||
}
|
||
|
||
function toggleBold() {
|
||
data.editorCtx?.format('bold', null)
|
||
appendLog('action', `请求切换加粗 => ${!data.boldActive}`)
|
||
}
|
||
|
||
function setAlignCenter() {
|
||
data.editorCtx?.format('align', 'center')
|
||
appendLog('action', '请求设置居中对齐')
|
||
}
|
||
|
||
function removeFormat() {
|
||
data.editorCtx?.removeFormat({
|
||
success: () => {
|
||
appendLog('action', '已清除当前样式')
|
||
},
|
||
fail: () => {
|
||
appendLog('error', '清除样式失败')
|
||
}
|
||
})
|
||
}
|
||
|
||
function clearEditor() {
|
||
data.editorCtx?.clear({
|
||
success: () => {
|
||
appendLog('action', '已清空编辑器内容')
|
||
},
|
||
fail: () => {
|
||
appendLog('error', '清空编辑器失败')
|
||
}
|
||
})
|
||
}
|
||
|
||
function blurEditor() {
|
||
data.editorCtx?.blur({
|
||
success: () => {
|
||
appendLog('action', '已主动触发失焦')
|
||
},
|
||
fail: () => {
|
||
appendLog('error', '主动失焦失败')
|
||
}
|
||
})
|
||
}
|
||
|
||
function hideKeyboardForTest() {
|
||
uni.hideKeyboard()
|
||
appendLog('keyboard', '已请求隐藏键盘')
|
||
}
|
||
|
||
function clearLogs() {
|
||
data.logs.splice(0, data.logs.length)
|
||
}
|
||
|
||
function testSetContentsHtml() {
|
||
data.editorCtx?.setContents({
|
||
html: '<p style="text-align:center;"><strong>Hello,uni-app x</strong></p><p>editor的setContents接口示例</p>',
|
||
success: () => {
|
||
appendLog('action', '成功设置富文本内容')
|
||
},
|
||
fail: (error: any) => {
|
||
appendLog('error', `setContents fail: ${JSON.stringify(error)}`)
|
||
}
|
||
})
|
||
}
|
||
|
||
defineExpose({
|
||
data,
|
||
getTypeLabel,
|
||
onReadOnlyChange,
|
||
onTypeChange,
|
||
onPlaceholderChange,
|
||
onDraftShowImgSizeChange,
|
||
onDraftShowImgToolbarChange,
|
||
onDraftShowImgResizeChange,
|
||
rebuildEditor,
|
||
insertSampleText,
|
||
insertMention,
|
||
insertSampleImage,
|
||
toggleBold,
|
||
setAlignCenter,
|
||
removeFormat,
|
||
clearEditor,
|
||
blurEditor,
|
||
hideKeyboardForTest,
|
||
updateEditorRect,
|
||
testSetContentsHtml
|
||
})
|
||
</script>
|
||
|
||
<style>
|
||
@import './editor-icon.css';
|
||
|
||
.page-root {
|
||
flex-direction: column;
|
||
flex: 1;
|
||
}
|
||
|
||
.preview-panel {
|
||
flex-direction: column;
|
||
padding: 10px;
|
||
background-color: #ffffff;
|
||
border-bottom-width: 1px;
|
||
border-bottom-style: solid;
|
||
border-bottom-color: rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.preview-header {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.preview-state-row {
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
margin-top: 6px;
|
||
}
|
||
|
||
.preview-toolbar {
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
margin-top: 10px;
|
||
padding-top: 8px;
|
||
padding-right: 8px;
|
||
padding-bottom: 8px;
|
||
border-radius: 6px;
|
||
background-color: #f5f6f8;
|
||
}
|
||
|
||
.preview-toolbar-item {
|
||
width: 36px;
|
||
height: 36px;
|
||
margin-top: 8px;
|
||
margin-left: 8px;
|
||
border-radius: 6px;
|
||
justify-content: center;
|
||
align-items: center;
|
||
background-color: #ffffff;
|
||
}
|
||
|
||
.preview-toolbar-item-active {
|
||
background-color: #e6f0ff;
|
||
}
|
||
|
||
.preview-toolbar-icon {
|
||
color: #333333;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.preview-toolbar-icon-active {
|
||
color: #007aff;
|
||
}
|
||
|
||
.preview-state-text {
|
||
margin-right: 12px;
|
||
color: #666666;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.preview-editor-box {
|
||
margin-top: 10px;
|
||
height: 150px;
|
||
border-width: 1px;
|
||
border-style: solid;
|
||
border-color: rgba(0, 0, 0, 0.08);
|
||
border-radius: 6px;
|
||
background-color: #ffffff;
|
||
}
|
||
|
||
.preview-editor {
|
||
height: 150px;
|
||
min-height: 0px;
|
||
padding: 10px;
|
||
}
|
||
|
||
.props-scroll {
|
||
flex: 1;
|
||
}
|
||
|
||
.button-list {
|
||
flex-direction: column;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.action-button {
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.apply-button {
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.event-header-row {
|
||
flex-direction: row;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.log-box {
|
||
flex-direction: column;
|
||
margin-top: 10px;
|
||
padding: 10px;
|
||
border-radius: 6px;
|
||
background-color: #ffffff;
|
||
}
|
||
|
||
.log-text {
|
||
margin-top: 6px;
|
||
color: #333333;
|
||
font-size: 12px;
|
||
line-height: 18px;
|
||
}
|
||
</style>
|