```
<el-row>
<el-col>
<span class="diver">详细内容</span>
<div class="editor-container">
<tinymce :height=400
ref="editor"
v-model="formValue.goods_contents"></tinymce>
</div>
</el-col>
</el-row>
```
```
import tinymce from "@/components/Tinymce"
```
```
components: {
tinymce
},
```
index.vue
```
E:/Vue7/shop805/src/components/Tinymce/index.vue
```
```
<template>
<div class="tinymce-container editor-container">
<textarea class="tinymce-textarea"
id="tinymceId"></textarea>
<div class="editor-custom-btn-container">
<editorImage color="#20a0ff"
class="editor-upload-btn"
@successCBK="imageSuccessCBK"></editorImage>
</div>
</div>
</template>
<script>
import editorImage from './components/editorImage'
export default {
name: 'tinymce',
components: { editorImage },
props: {
value: {
type: String,
default: ''
},
toolbar: {
type: Array,
required: false,
default() {
return ['removeformat undo redo | bullist numlist | outdent indent | forecolor | fullscreen code', 'bold italic blockquote | h2 p media link | alignleft aligncenter alignright ']
}
},
menubar: {
default: ''
},
height: {
type: Number,
required: false,
default: 360
}
},
data() {
return {
hasChange: false,
hasInit: false,
}
},
watch: {
value(val) {
if (!this.hasChange && this.hasInit) {
this.$nextTick(() => window.tinymce.get('tinymceId').setContent(val))
}
}
},
mounted() {
this.initTinymce()
},
activated() {
this.initTinymce()
},
deactivated() {
this.destroyTinymce()
},
methods: {
initTinymce() {
const _this = this
window.tinymce.init({
selector: '#tinymceId',
height: this.height,
body_class: 'panel-body ',
object_resizing: false,
toolbar: this.toolbar,
menubar: this.menubar,
plugins: 'advlist,autolink,code,paste,textcolor, colorpicker,fullscreen,link,lists,media,wordcount, imagetools ',
// language: 'zh_CN',
// language_url: 'http://cdn.masterjoy.top/zh_CN.js',
forced_root_block: '',
end_container_on_empty_block: true,
powerpaste_word_import: 'clean',
code_dialog_height: 450,
code_dialog_width: 1000,
advlist_bullet_styles: 'square',
advlist_number_styles: 'default',
imagetools_cors_hosts: ['wpimg.wallstcn.com', 'wallstreetcn.com'],
imagetools_toolbar: 'watermark',
default_link_target: '_blank',
link_title: false,
init_instance_callback: editor => {
if (_this.value) {
editor.setContent(_this.value)
}
_this.hasInit = true
editor.on('NodeChange Change KeyUp', () => {
this.hasChange = true
this.$emit('input', editor.getContent({ format: 'raw' }))
})
}
// 整合七牛上传
// images_dataimg_filter(img) {
// setTimeout(() => {
// const $image = $(img);
// $image.removeAttr('width');
// $image.removeAttr('height');
// if ($image[0].height && $image[0].width) {
// $image.attr('data-wscntype', 'image');
// $image.attr('data-wscnh', $image[0].height);
// $image.attr('data-wscnw', $image[0].width);
// $image.addClass('wscnph');
// }
// }, 0);
// return img
// },
// images_upload_handler(blobInfo, success, failure, progress) {
// progress(0);
// const token = _this.$store.getters.token;
// getToken(token).then(response => {
// const url = response.data.qiniu_url;
// const formData = new FormData();
// formData.append('token', response.data.qiniu_token);
// formData.append('key', response.data.qiniu_key);
// formData.append('file', blobInfo.blob(), url);
// upload(formData).then(() => {
// success(url);
// progress(100);
// })
// }).catch(err => {
// failure('出现未知问题,刷新页面,或者联系程序员')
// console.log(err);
// });
// },
})
},
destroyTinymce() {
if (window.tinymce.get('tinymceId')) {
window.tinymce.get('tinymceId').destroy()
}
},
setContent(value) {
window.tinymce.get('tinymceId').setContent(value)
},
getContent() {
window.tinymce.get('tinymceId').getContent()
},
imageSuccessCBK(arr) {
arr.forEach(v => {
window.tinymce.get('tinymceId').insertContent(`<img class="wscnph" src="${v.url}" >`)
})
}
},
destroyed() {
this.destroyTinymce()
}
}
</script>
<style scoped>
.tinymce-container {
position: relative;
}
.tinymce-textarea {
visibility: hidden;
z-index: -1;
}
.editor-custom-btn-container {
position: absolute;
right: 15px;
/*z-index: 2005;*/
top: 18px;
}
.editor-upload-btn {
display: inline-block;
}
</style>
```
```
components/Tinymce/components/editorImage.vue
```
```
<template>
<div class="upload-container">
<el-button icon='upload'
:style="{background:color,borderColor:color}"
@click=" dialogVisible=true"
type="primary">上传图片
</el-button>
<el-dialog :visible.sync="dialogVisible"
title="上传图片">
<el-upload class="editor-slide-upload"
:action="imgPostUrl"
:multiple="true"
:file-list="fileList"
:show-file-list="true"
list-type="picture-card"
:on-remove="handleRemove"
:on-success="handleSuccess"
:before-upload="beforeUpload">
<el-button size="small"
type="primary">点击上传</el-button>
</el-upload>
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary"
@click="handleSubmit">确 定</el-button>
</el-dialog>
</div>
</template>
<script>
// import { getToken } from 'api/qiniu'
const api = process.env.BASE_API
const cdn = process.env.CDN
export default {
name: 'editorSlideUpload',
props: {
color: {
type: String,
default: '#20a0ff'
}
},
data() {
return {
dialogVisible: false,
listObj: {},
fileList: [],
imgPostUrl: api + '/common/uploadImg', //图片上传地址
}
},
methods: {
checkAllSuccess() {
return Object.keys(this.listObj).every(item => this.listObj[item].hasSuccess)
},
handleSubmit() {
const arr = Object.keys(this.listObj).map(v => this.listObj[v])
if (!this.checkAllSuccess()) {
this.$message('请等待所有图片上传成功 或 出现了网络问题,请刷新页面重新上传!')
return
}
console.log(arr)
this.$emit('successCBK', arr)
this.listObj = {}
this.fileList = []
this.dialogVisible = false
},
handleSuccess(response, file) {
const uid = file.uid
const objKeyArr = Object.keys(this.listObj)
for (let i = 0, len = objKeyArr.length; i < len; i++) {
if (this.listObj[objKeyArr[i]].uid === uid) {
this.listObj[objKeyArr[i]].url = cdn + response.data
this.listObj[objKeyArr[i]].hasSuccess = true
return
}
}
},
handleRemove(file) {
const uid = file.uid
const objKeyArr = Object.keys(this.listObj)
for (let i = 0, len = objKeyArr.length; i < len; i++) {
if (this.listObj[objKeyArr[i]].uid === uid) {
delete this.listObj[objKeyArr[i]]
return
}
}
},
beforeUpload(file) {
const _self = this
const _URL = window.URL || window.webkitURL
const fileName = file.uid
this.listObj[fileName] = {}
return new Promise((resolve, reject) => {
const img = new Image()
img.src = _URL.createObjectURL(file)
img.onload = () => {
_self.listObj[fileName] = { hasSuccess: false, uid: file.uid, width: this.width, height: this.height }
}
resolve(true)
})
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.upload-container {
.editor-slide-upload {
margin-bottom: 20px;
}
}
</style>
```
- webpack-dev-server不是内部或外部命令
- vue+ele添加笑脸表情
- from UglifyJs Unexpected token: punc (()
- vmodel-ref
- jscopy
- watch_or_computed
- checkbox-group
- array_filter
- array many filter
- js array unshift
- vue watch one
- sku
- edit-button
- el-select clearable placeholder
- 必填
- 如何设置一个索引从1开始
- Injection "elForm" not found
- $refs
- resetFields
- table 二级数据
- Table 合并
- switch 开关
- radio group 单选
- 二级菜单
- 访问页面出错后退到上一页
- 编辑器tinymce
- v-for从1开始索引
- 图片绑定路径
- 分栏间隔
- class绑定card底色
- 动态增减表单项
- watch deep
- form 获取值
- table索引方法
- table两个改一个另一个也跟着变解决方法
- table标题改整列
- vue echarts