Demo:右键菜单新增复制到剪贴板功能
This commit is contained in:
parent
1fc5b951a0
commit
b7722987b1
@ -207,7 +207,7 @@ export const copyNodeTree = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 图片转成dataURL
|
// 图片转成dataURL
|
||||||
export const imgToDataUrl = src => {
|
export const imgToDataUrl = (src, returnBlob = false) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const img = new Image()
|
const img = new Image()
|
||||||
// 跨域图片需要添加这个属性,否则画布被污染了无法导出图片
|
// 跨域图片需要添加这个属性,否则画布被污染了无法导出图片
|
||||||
@ -220,7 +220,13 @@ export const imgToDataUrl = src => {
|
|||||||
let ctx = canvas.getContext('2d')
|
let ctx = canvas.getContext('2d')
|
||||||
// 图片绘制到canvas里
|
// 图片绘制到canvas里
|
||||||
ctx.drawImage(img, 0, 0, img.width, img.height)
|
ctx.drawImage(img, 0, 0, img.width, img.height)
|
||||||
resolve(canvas.toDataURL())
|
if (returnBlob) {
|
||||||
|
canvas.toBlob(blob => {
|
||||||
|
resolve(blob)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
resolve(canvas.toDataURL())
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reject(e)
|
reject(e)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,7 +100,15 @@ export default {
|
|||||||
removeNote: 'Remove note',
|
removeNote: 'Remove note',
|
||||||
removeCustomStyles: 'Remove custom styles',
|
removeCustomStyles: 'Remove custom styles',
|
||||||
removeAllNodeCustomStyles: 'Remove all node custom styles',
|
removeAllNodeCustomStyles: 'Remove all node custom styles',
|
||||||
exportNodeToPng: 'Export node to png'
|
exportNodeToPng: 'Export node to png',
|
||||||
|
copyToClipboard: 'Copy to clipboard',
|
||||||
|
copyToSmm: 'SMM',
|
||||||
|
copyToJson: 'JSON',
|
||||||
|
copyToMarkdown: 'Markdown',
|
||||||
|
copyToTxt: 'Txt',
|
||||||
|
copyToPng: 'Png',
|
||||||
|
copySuccess: 'Copy success',
|
||||||
|
copyFail: 'Copy fail'
|
||||||
},
|
},
|
||||||
count: {
|
count: {
|
||||||
words: 'Words',
|
words: 'Words',
|
||||||
|
|||||||
@ -100,7 +100,15 @@ export default {
|
|||||||
removeNote: '移除备注',
|
removeNote: '移除备注',
|
||||||
removeCustomStyles: '一键去除自定义样式',
|
removeCustomStyles: '一键去除自定义样式',
|
||||||
removeAllNodeCustomStyles: '一键去除所有节点自定义样式',
|
removeAllNodeCustomStyles: '一键去除所有节点自定义样式',
|
||||||
exportNodeToPng: '导出该节点为图片'
|
exportNodeToPng: '导出该节点为图片',
|
||||||
|
copyToClipboard: '复制到剪贴板',
|
||||||
|
copyToSmm: 'SMM',
|
||||||
|
copyToJson: 'JSON',
|
||||||
|
copyToMarkdown: 'Markdown',
|
||||||
|
copyToTxt: 'Txt',
|
||||||
|
copyToPng: '图片',
|
||||||
|
copySuccess: '复制成功',
|
||||||
|
copyFail: '复制失败'
|
||||||
},
|
},
|
||||||
count: {
|
count: {
|
||||||
words: '字数',
|
words: '字数',
|
||||||
|
|||||||
@ -109,6 +109,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<span class="name">{{ $t('contextmenu.expandTo') }}</span>
|
<span class="name">{{ $t('contextmenu.expandTo') }}</span>
|
||||||
|
<span class="el-icon-arrow-right"></span>
|
||||||
<div class="subItems listBox" :class="{ isDark: isDark }">
|
<div class="subItems listBox" :class="{ isDark: isDark }">
|
||||||
<div
|
<div
|
||||||
class="item"
|
class="item"
|
||||||
@ -137,13 +138,30 @@
|
|||||||
$t('contextmenu.removeAllNodeCustomStyles')
|
$t('contextmenu.removeAllNodeCustomStyles')
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<span class="name">{{ $t('contextmenu.copyToClipboard') }}</span>
|
||||||
|
<span class="el-icon-arrow-right"></span>
|
||||||
|
<div class="subItems listBox" :class="{ isDark: isDark }">
|
||||||
|
<div
|
||||||
|
class="item"
|
||||||
|
v-for="item in copyList"
|
||||||
|
:key="item.value"
|
||||||
|
@click="copyToClipboard(item.value)"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapMutations } from 'vuex'
|
import { mapState, mapMutations } from 'vuex'
|
||||||
import { getTextFromHtml } from 'simple-mind-map/src/utils'
|
import { getTextFromHtml, imgToDataUrl } from 'simple-mind-map/src/utils'
|
||||||
|
import { transformToMarkdown } from 'simple-mind-map/src/parse/toMarkdown'
|
||||||
|
import { transformToTxt } from 'simple-mind-map/src/parse/toTxt'
|
||||||
|
import { setDataToClipboard, setImgToClipboard, copy } from '@/utils'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 王林
|
* @Author: 王林
|
||||||
@ -166,7 +184,8 @@ export default {
|
|||||||
type: '',
|
type: '',
|
||||||
isMousedown: false,
|
isMousedown: false,
|
||||||
mosuedownX: 0,
|
mosuedownX: 0,
|
||||||
mosuedownY: 0
|
mosuedownY: 0,
|
||||||
|
enableCopyToClipboardApi: navigator.clipboard
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -184,6 +203,33 @@ export default {
|
|||||||
this.$t('contextmenu.level6')
|
this.$t('contextmenu.level6')
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
copyList() {
|
||||||
|
const list = [
|
||||||
|
{
|
||||||
|
name: this.$t('contextmenu.copyToSmm'),
|
||||||
|
value: 'smm'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: this.$t('contextmenu.copyToJson'),
|
||||||
|
value: 'json'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: this.$t('contextmenu.copyToMarkdown'),
|
||||||
|
value: 'md'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: this.$t('contextmenu.copyToTxt'),
|
||||||
|
value: 'txt'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
if (this.enableCopyToClipboardApi) {
|
||||||
|
list.push({
|
||||||
|
name: this.$t('contextmenu.copyToPng'),
|
||||||
|
value: 'png'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
},
|
||||||
insertNodeBtnDisabled() {
|
insertNodeBtnDisabled() {
|
||||||
return !this.node || this.node.isRoot || this.node.isGeneralization
|
return !this.node || this.node.isRoot || this.node.isGeneralization
|
||||||
},
|
},
|
||||||
@ -355,6 +401,48 @@ export default {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
this.hide()
|
this.hide()
|
||||||
|
},
|
||||||
|
|
||||||
|
// 复制到剪贴板
|
||||||
|
async copyToClipboard(type) {
|
||||||
|
try {
|
||||||
|
this.hide()
|
||||||
|
let data
|
||||||
|
let str
|
||||||
|
switch (type) {
|
||||||
|
case 'smm':
|
||||||
|
case 'json':
|
||||||
|
data = this.mindMap.getData(true)
|
||||||
|
str = JSON.stringify(data)
|
||||||
|
break
|
||||||
|
case 'md':
|
||||||
|
data = this.mindMap.getData()
|
||||||
|
str = transformToMarkdown(data)
|
||||||
|
break
|
||||||
|
case 'txt':
|
||||||
|
data = this.mindMap.getData()
|
||||||
|
str = transformToTxt(data)
|
||||||
|
break
|
||||||
|
case 'png':
|
||||||
|
const png = await this.mindMap.export('png', false)
|
||||||
|
const blob = await imgToDataUrl(png, true)
|
||||||
|
setImgToClipboard(blob)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (str) {
|
||||||
|
if (this.enableCopyToClipboardApi) {
|
||||||
|
setDataToClipboard(str)
|
||||||
|
} else {
|
||||||
|
copy(str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$message.success(this.$t('contextmenu.copySuccess'))
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
this.$message.error(this.$t('contextmenu.copyFail'))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -393,11 +481,11 @@ export default {
|
|||||||
.item {
|
.item {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
line-height: 28px;
|
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
&.danger {
|
&.danger {
|
||||||
color: #f56c6c;
|
color: #f56c6c;
|
||||||
@ -439,6 +527,7 @@ export default {
|
|||||||
left: 100%;
|
left: 100%;
|
||||||
top: 0;
|
top: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
width: 150px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,11 +49,28 @@ export const fileToBuffer = file => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 复制文本到剪贴板
|
// 复制文本到剪贴板
|
||||||
export const copy = (text) => {
|
export const copy = text => {
|
||||||
const input = document.createElement('input')
|
// 使用textarea可以保留换行
|
||||||
input.setAttribute('value', text)
|
const input = document.createElement('textarea')
|
||||||
|
// input.setAttribute('value', text)
|
||||||
|
input.innerHTML = text
|
||||||
document.body.appendChild(input)
|
document.body.appendChild(input)
|
||||||
input.select()
|
input.select()
|
||||||
document.execCommand('copy')
|
document.execCommand('copy')
|
||||||
document.body.removeChild(input)
|
document.body.removeChild(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 复制文本到剪贴板
|
||||||
|
export const setDataToClipboard = data => {
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
navigator.clipboard.writeText(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复制图片到剪贴板
|
||||||
|
export const setImgToClipboard = img => {
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
const data = [new ClipboardItem({ ['image/png']: img })]
|
||||||
|
navigator.clipboard.write(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user