作者: yongchao, li

  • Nuxt 刷新使用富文本 报错 Document / Window not defined 究极解决方案

    安装方法:npm install -d vue-quill-editor quill vue-cropper

    官网:

    vue-quill-editor:https://quilljs.com/

    git:https://github.com/surmon-china/vue-quill-editor

    vue-cropper:https://github.com/xyxiao001/vue-cropper

    nuxt框架基于vue的服务端渲染,有报错 Document / Window not defined 的问题,使用富文本编辑器进行组件单独引入的时候会报错,在组件中使用

    if (process.client) {
      require('external_library')
    }

    之后element会显示不出来,所以在使用这种引入插件的时候建议直接在

    plugins文件夹内直接全局注册,使用服务器渲染
    plugins: [
        '@/plugins/element-ui',
        '@/plugins/bootstrap-vue',
        { src: '@/plugins/map', ssr: false },
        { src: '@/plugins/vue-quill-editor', ssr: false },
        { src: '@/plugins/vue-cropper', ssr: false }
      ],

    组件使用代码:(网上摘取)

    在使用上传的时候action是传输一个链接地址,如果想根据自己定义的axios上传需要添加一个auto-upload=”false”意思不取消自动上传更据:on-change=”onChange”(文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用)动作进行上传

    <template>
      <div>
        <!-- 图片上传组件-->
        <el-upload
          :before-upload="beforeUpload"
          :show-file-list="false"
          accept="image/*"
          action=""
          class="avatar-uploader"
          hidden
          name="file"
          type='file'>
          <el-button size="small" type="primary">点击上传图片 到 文本编辑器</el-button>
        </el-upload>
        <!-- 编辑器组件-->
        <quill-editor
          :options="editorOption"
          @change="onEditorChange($event)"
          class="editor"
          ref="myQuillEditor"
          v-model="content">
        </quill-editor>
        <!-- 图片裁剪组件-->
        <el-dialog :visible.sync="isShowCropper" top="5vh">
          <VueCropper
            :autoCrop="option.autoCrop"
            :autoCropHeight="option.autoCropHeight"
            :autoCropWidth="option.autoCropWidth"
            :canScale="option.canScale"
            :fixed="option.fixed"
            :fixedNumber="option.fixedNumber"
            :img="option.img"
            :info="option.info"
            :outputSize="option.outputSize"
            :outputType="option.outputType"
            ref="cropper"
            style="height:600px;margin:20px 0"
          >
          </VueCropper>
          <br/>
    
          <el-button @click="onCubeImg()" type="primary">生成图片</el-button>
          <el-button @click="isShowCropper = false">取消</el-button>
        </el-dialog>
      </div>
    </template>
    <script>
      // 富文本工具栏配置
      const toolbarOptions = [
        ['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线
        ['blockquote', 'code-block'], // 引用  代码块
        [{ header: 1 }, { header: 2 }], // 1、2 级标题
        [{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表
        [{ script: 'sub' }, { script: 'super' }], // 上标/下标
        [{ indent: '-1' }, { indent: '+1' }], // 缩进
        // [{'direction': 'rtl'}],                         // 文本方向
        [{ size: ['small', false, 'large', 'huge'] }], // 字体大小
        [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
        [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
        [{ font: [] }], // 字体种类
        [{ align: [] }], // 对齐方式
        ['clean'], // 清除文本格式
        ['link', 'image', 'video'] // 链接、图片、视频
      ]
    
    
      import 'quill/dist/quill.core.css'
      import 'quill/dist/quill.snow.css'
      import 'quill/dist/quill.bubble.css'
      import { uImage } from '@/api/uploadImage.js'
    
      export default {
        name: 'textEditor',
        components: {},
        props: {
          /*编辑器的内容*/
          value: {
            type: String
          },
          /*图片大小*/
          maxSize: {
            type: Number,
            default: 4000 //kb
          }
        },
        data() {
          return {
            // 富文本数据
            content: '',
            quillUpdateImg: false, // 根据图片上传状态来确定是否显示loading动画,刚开始是false,不显示
            editorOption: {
              theme: 'snow', // or 'bubble'
              placeholder: '请输入您想输入的内容',
              modules: {
                toolbar: {
                  container: toolbarOptions,
                  // 和上传按钮进行绑定
                  handlers: {
                    image: function(value) {
                      console.log(value)
                      if (value) {
                        // 触发input框选择图片文件
                        document.querySelector('.avatar-uploader input').click()
                      } else {
                        this.quill.format('image', false)
                      }
                    }
                  }
                }
              }
            },
            // 切图器数据
            option: {
              img: '',                         // 裁剪图片的地址
              info: true,                      // 裁剪框的大小信息
              outputSize: 1,                   // 裁剪生成图片的质量
              outputType: 'png',               // 裁剪生成图片的格式
              canScale: true,                 // 图片是否允许滚轮缩放
              autoCrop: true,                  // 是否默认生成截图框
              autoCropWidth: 150,              // 默认生成截图框宽度
              autoCropHeight: 150,             // 默认生成截图框高度
              fixed: true,                    // 是否开启截图框宽高固定比例
              fixedNumber: [4, 4]             // 截图框的宽高比例
            },
            isShowCropper: false,
            isClient: true,
            width: '150px',
            height: '150px'
          }
        },
        methods: {
          // 上传切图前调用
          beforeUpload(file) {
            /**
             * URL.createObjectURL(file)生成本地的url
             * 返回false终止了自动上传
             * */
            this.option.img = URL.createObjectURL(file)
            this.option.autoCropWidth = this.width
            this.option.autoCropHeight = this.height
            this.isShowCropper = true
            return false
          },
          // 确定裁剪图片
          onCubeImg() {
            // 获取cropper的截图的base64 数据data
            this.$refs.cropper.getCropData(data => {
              //截取bas64 截取base64的格式 和 图片的后缀名
              let baseSplit= data.split(',')
              let format = baseSplit[0].split('/')[1].split(';')[0]
              //获取base64格式的信息
              let base = ''
              if (process.client) {
                base = window.atob(baseSplit[1])
              }
              //转格式:base64转图片
              /**
               *格式为:File
               * lastModified: 1593134876792
               * lastModifiedDate: Fri Jun 26 2020 09:27:56 GMT+0800 (中国标准时间) {}
               * name: "img.png"
               * size: 15407
               * type: "image/png"
               * webkitRelativePath: ""
               * */
              let index = base.length
              let u8arr = new Uint8Array(index)
              while (index--) {
                u8arr[index] = base.charCodeAt(index)
              }
              let blods = new File([u8arr],'img.' + format,{type: 'image/' + format })
    
              /**
               * 建立一个formData表单,之后把上面的base64转换后的格式使用append传递给FormData
               * */
              let fromData = new FormData()
              fromData.append('file',blods)
    
              this.$notify({
                title: '成功',
                message: '正在上传中',
                type: 'success'
              });
              //发出网络请求
              uImage(fromData).then(res => {
                this.$notify({
                  title: '成功',
                  message: '图片上传成功',
                  type: 'success'
                });
                // 获取富文本组件实例
                let quill = this.$refs.myQuillEditor.quill
                if(res.code === 200){
                  // 获取光标所在位置
                  /**
                   *  quill.insertEmbed(length, 'image', res.data.url)
                   *  图片显示的位置,根据length后的位置显示
                   * */
                  if (quill.getSelection() && quill.getSelection().index) {
                    let length = quill.getSelection().index
                    quill.insertEmbed(length, 'image', res.data.url)
                  } else {
                    let length = 0
                    quill.insertEmbed(length, 'image', res.data.url)
                  }
                  // 调整光标到最后
                  quill.setSelection(length + 1)
                }else {
                  console.log(res.data.code)
                  this.$notify({
                    title: '警告',
                    message: '图片上传失败',
                    type: 'warning'
                  });
                }
                this.isShowCropper = false
                // 先将显示图片地址清空,防止重复显示
                this.option.img = ''
              })
            })
          },
          onEditorChange() {
    
            console.log(this.content)
            //富文本内容改变事件 发送给父级元素
            this.$emit('change', this.content)
          }
        },
        mounted() {
          setTimeout(() => {
            this.content = this.value
          }, 500)
        }
      }
    </script>
    <style lang="scss">
    
    </style>
    
    

     

  • Nuxt.js使用百度地图vue-baidu-map

    vue-baidu-map文档:https://dafrok.github.io/vue-baidu-map/#/zh/start/usage

    安装vue-baidu-map:npm i vue-baidu-map -D

    在plugins新建map.js:(名字是,map.js):

    import BaiduMap from 'vue-baidu-map'
    import Vue from 'vue'
    Vue.use(BaiduMap, {
      ak: '申请的百度地图密匙'
    })

    在页面中使用:

    <template>
      <div>
        <baidu-map class="bdwindow" :dragging="dragging" :center="center" :zoom="zoom" style="height:500px" :scroll-wheel-zoom='scroll'>
              <bm-info-window :position="center" :title="title" :show="show">
                  <p class="bdwtext" v-html="contents"></p>
              </bm-info-window>
        </baidu-map>
      </div>
    </template>
    <script>
    export default {
      data () {
            return {
                jump_path:"",
                center: {lng: 120.4373010751, lat: 23.1095638170},
                zoom: 15,  //缩放级别
                title:"标题",
                contents: '地址:具体地址信息',  //标签内容
                show: true,  //显示标签
                scroll:true,  //地图缩放
                dragging:true,  //地图拖拽
            }
        }
    }
    </script>