• element-ui 上传组件el-upload的再次封装 并支持图片的上传后的裁剪功能


      1 <!-- @format -->
      2 
      3 <template>
      4   <div>
      5     <!-- <input type="file" v-show="false"  @change="change" /> -->
      6     <!-- 生产环境 -->
      7     <!-- action="http://cystorage.cycore.cn/v2/files/upload" -->
      8     <!-- 测试环境 -->
      9     <!-- action="http://cystorage.whhlj2test.changyan.cn/v2/files/upload" -->
     10     <el-upload
     11       ref="elUpload"
     12       :class="className"
     13       :action="url"
     14       :accept="accept"
     15       :before-upload="beforeUpload"
     16       :limit="limit"
     17       :multiple="multiple"
     18       :file-list='fileList'
     19       :data='token'
     20       :show-file-list="showFileList"
     21       :list-type="listType"
     22       :on-exceed="handleExceed"
     23       :on-progress="handleProgress"
     24       :on-success='handleFileSuccess'
     25       :on-preview="handlePictureCardPreview"
     26       :on-remove="handleRemove"
     27       :on-error="handleError"
     28       :on-change="handleFileChange">
     29       <slot></slot>
     30     </el-upload>
     31   </div>
     32 </template>
     33 
     34 <script>
     35 import axios from '@/plugins/axios';
     36 export default {
     37   props: {
     38     uploadType: {
     39       type: String,
     40       default: 'uploadToken'
     41     },
     42     listType: {
     43       type: String,
     44       default: ''
     45     },
     46     type: {
     47       type: String,
     48       default: ''
     49     },
     50     accept: {
     51       type: String,
     52       default: ''
     53     },
     54     limit: {
     55       type: Number
     56     },
     57     multiple: {
     58       type: Boolean,
     59       default: false
     60     },
     61     className: {
     62       type: String,
     63       default: 'upload-demo'
     64     },
     65     showFileList: {
     66       type: Boolean,
     67       default: true
     68     },
     69     fileList: {
     70       type: Array,
     71       default: () => {
     72         return [];
     73       }
     74     },
     75     beforeAvatarUpload: {
     76       type: Function
     77     }
     78   },
     79   data() {
     80     return {
     81       token: {},
     82       url: 'http://cystorage.whhlj2test.changyan.cn/v2/files/upload'
     83     };
     84   },
     85   methods: {
     86     async beforeUpload(file) {
     87       let rules = false;
     88       let fileType = file.name.substring(file.name.lastIndexOf('.') + 1);
     89       rules = this.beforeAvatarUpload(file, fileType);
     90       if (!rules) {
     91         return Promise.reject();
     92       }
     93       let tokenize = await this.$api['common/tokenize']({
     94         fileExt: fileType
     95       });
     96       this.token = tokenize['uploadToken'];
     97 
     98       return Promise.resolve();
     99     },
    100     handleFileSuccess(res, file, fileList) {
    101       this.$emit('handleFileSuccess', res, file, fileList, this.type);
    102     },
    103     handlePictureCardPreview(file) {
    104       if (this.type == 'cover') {
    105         this.$emit('handlePictureCardPreview', file);
    106       }
    107     },
    108     handleFileChange(file, fileList) {
    109       if (this.type == 'cover') {
    110         this.$emit('handleFileChange', file, fileList);
    111       } else {
    112         this.$emit('handleUploadChange', file, fileList);
    113       }
    114     },
    115     handleExceed(files, fileList) {
    116       this.$emit('handleExceed', files, fileList);
    117     },
    118     handleRemove(file, fileList) {
    119       this.$emit('handleRemove', file, fileList, this.type);
    120     },
    121     handleProgress(event, file, fileList) {
    122       this.$emit('handleProgress', event, file, fileList);
    123     },
    124     handleError(err, file, fileList) {
    125       this.$emit('handleError', err, file, fileList);
    126     },
    127     handleUrl() {
    128       let baseUrl = window.location.href;
    129       let baseUrlArr = [];
    130       baseUrlArr = baseUrl.split('#');
    131       baseUrl = baseUrlArr[0];
    132       if (baseUrl.indexOf('jichugroup') > -1) {
    133         this.url = 'http://cystorage.cycore.cn/v2/files/upload';
    134       } else {
    135         this.url = 'http://cystorage.sdfztest.changyan.cn/v2/files/upload';
    136       }
    137     }
    138   },
    139   created() {
    140     this.handleUrl();
    141   }
    142 };
    143 </script>
    144 
    145 <style lang="less" scoped>
    146 </style>

    在调用该组件的地方 这样写

       1 <!-- @format -->
       2 <!-- 创建活动 -->
       3 
       4 <template>
       5   <div>
       6     <el-form class="create-form"
       7              :model="dataForm"
       8              :rules="dataRule"
       9              ref="ruleForm"
      10              label-width="110px">
      11       <FromBlock :blockObj="{title:'基础设置',tip:'',showBtn:false}">
      12           <div>
      13             <el-form-item label="活动主题:" prop="title">
      14               <el-input v-model="dataForm.title" placeholder="请输入活动主题"></el-input>
      15             </el-form-item>
      16             <el-form-item label="封面图片:" prop="cover">
      17               <MyUpload 
      18               v-show="!cutImgShow"
      19               :type="'cover'"
      20               :className="'avatar-uploader'"
      21               :listType="'picture-card'"
      22               :accept="'jpg,png,jpeg,bpm'"
      23               :fileList="coverList"
      24               :beforeAvatarUpload='beforeAvatarUploadImg'
      25               @handleFileSuccess="handleFileSuccess"
      26               @handlePictureCardPreview="handlePictureCardPreview"
      27               @handleRemove="handleRemove"
      28               @handleFileChange="handleFileChange"
      29               >
      30                 <i class="el-icon-plus avatar-uploader-icon"></i>
      31                 <span slot="tip" class="el-upload__tip upload-tip">封面尺寸比例应为77:20</span>
      32               </MyUpload>
      33               <el-dialog :visible.sync="dialogVisible">
      34                   <img width="100%" :src="dialogImageUrl" alt="">
      35                 </el-dialog>
      36                 <div v-if="cutImgShow">
      37                   <cropper v-if="dataForm.cover.length===0" :Setting="setting" @cutImg="getCutUrl"></cropper>
      38                   <div v-if="dataForm.cover.length >0 ">
      39                     <img class="cut-img-view" :src="dataForm.cover" alt="头像">
      40                   </div>
      41                   <div class="btn-wrap" :class="{'handle-cutimg-btn':dataForm.cover.length>0}">
      42                     <a class="form-btn btn-submit" v-if="dataForm.cover.length===0 && !showSubmit" @click="keepCutImg">保存</a>
      43                     <a class="form-btn btn-submit1" v-if="showSubmit">裁剪中...</a>
      44                     <a class="form-btn btn-cancel2" @click="cancelCutImg">取消</a>
      45                   </div>
      46                 </div>
      47             </el-form-item>
      48             <el-form-item label="活动时间:" prop="activityTime">
      49               <el-date-picker
      50                 v-model="dataForm.activityTime"
      51                 type="datetimerange"
      52                 align="right"
      53                 @change="handleActivityTime"
      54                 start-placeholder="开始日期"
      55                 end-placeholder="结束日期"
      56                 format="yyyy-MM-dd HH:mm"
      57                 value-format="yyyy-MM-dd HH:mm:ss">
      58               </el-date-picker>
      59             </el-form-item>
      60             <el-form-item label="活动地址:">
      61               <el-input 
      62                 v-model="dataForm.address" 
      63                 placeholder="请输入活动地址"
      64                 maxlength="50"
      65                 show-word-limit></el-input>
      66             </el-form-item>
      67             <el-form-item label="活动类型:" prop="typeList">
      68               <el-select v-model="dataForm.typeList" multiple :multiple-limit="3" placeholder="请添加活动类型">
      69                 <el-option
      70                   v-for="(item,index) in activityType"
      71                   :key="index"
      72                   :label="item.name"
      73                   :value="item.id">
      74                 </el-option>
      75               </el-select>
      76               <span class="icon-set" @click="openAddType"></span>
      77             </el-form-item>
      78             <el-form-item label="活动介绍:">
      79               <el-input
      80                 type="textarea"
      81                 placeholder="请输入活动介绍"
      82                 v-model="dataForm.introduce"
      83                 maxlength="1000"
      84                 :rows="6"
      85                 show-word-limit
      86               >
      87               </el-input>
      88             </el-form-item>
      89             <el-form-item label="活动对象:">
      90               <el-input 
      91                 v-model="dataForm.actGroup" 
      92                 maxlength="40"
      93                 show-word-limit 
      94                 placeholder="请输入活动对象 ">
      95               </el-input>
      96               <span class="tip-message">需要强制限制报名范围,需在限制报名范围中设置</span>
      97             </el-form-item>
      98             <el-form-item label="活动人数:" prop="joinNum">
      99                <el-input-number class="input-number" v-model="dataForm.joinNum" :precision="0" :min="0" :step="10" :max="10000"></el-input-number>
     100                <span class="tip-message ml10">不填则不限制人数</span>
     101             </el-form-item>
     102             <el-form-item label="活动附件:">
     103               <MyUpload 
     104               class="file-name"
     105               :listType="''"
     106               :fileList="fileList"
     107               :limit="10"
     108               :beforeAvatarUpload='beforeAvatarUpload'
     109               @handleExceed="handleExceed"
     110               @handleFileSuccess="handleFileSuccess"
     111               @handleRemove="handleRemove"
     112               >
     113                 <el-button size="small" type="primary">点击上传</el-button>
     114                 <div slot="tip" class="el-upload__tip">支持扩展名:rar、zip、doc、docx、pdf、jpg......</div>
     115               </MyUpload>
     116             </el-form-item> 
     117           </div>
     118       </FromBlock>
     119       <FromBlock 
     120         :blockObj="{title:'限制报名范围',tip:'不填则默认全集团校范围下均可自由报名',showBtn:true}"
     121         @handleCheckChange="handleCheckChange"
     122         >
     123           <div>
     124             <el-tabs type="border-card">
     125               <el-tab-pane label="添加学生">
     126                 <div class="tree-box clearfix">
     127                   <div class="tree-left fl">
     128                     <div>全体学生</div>
     129                     <div>
     130                       <!-- <el-input
     131                           style="260px;"
     132                           placeholder="请输入老师名字"
     133                           suffix-icon="el-icon-search"
     134                           v-model="namVal">
     135                         </el-input> -->
     136                       <el-tree
     137                         :data="classTree"
     138                         :filter-node-method="filterNode"
     139                         show-checkbox
     140                         default-expand-all
     141                         node-key="id"
     142                         ref="classTree"
     143                         highlight-current
     144                         :default-checked-keys="checkedKeys"
     145                         @check="handleCheck"
     146                         :props="defaultProps">
     147                       </el-tree>
     148                     </div>
     149                   </div>
     150                   <div class="tree-center fl"></div>
     151                   <div class="tree-right fl">
     152                     <div>已选中</div>
     153                     <div>
     154                        <el-table
     155                           :data="tableData"
     156                           style=" 100%;">
     157                           <el-table-column
     158                             prop="schoolName"
     159                             label="学校名称"
     160                             width="140">
     161                           </el-table-column>
     162                           <el-table-column
     163                             prop="areaName"
     164                             label="校区名称"
     165                             width="140">
     166                           </el-table-column>
     167                           <el-table-column
     168                             prop="grade"
     169                             label="年级">
     170                           </el-table-column>
     171                           <el-table-column
     172                             prop="class"
     173                             label="班级">
     174                           </el-table-column>
     175                            <el-table-column
     176                            width="60"
     177                             label="操作">
     178                             <template slot-scope="scope">
     179                               <span @click="handleDel(scope.row.id,scope.$index)" class="icon-del"></span>
     180                             </template>
     181                           </el-table-column>
     182                         </el-table>
     183                     </div>
     184                   </div>
     185                 </div>
     186               </el-tab-pane>
     187             </el-tabs>
     188           </div>
     189       </FromBlock>
     190       <FromBlock :blockObj="{title:'高级设置',tip:'不填则无限制条件',showBtn:true}">
     191           <div>
     192             <el-form-item label="报名开始时间:">
     193               <el-date-picker
     194                 v-model="dataForm.enterBeginTime"
     195                 type="datetime"
     196                 placeholder="请选择报名开始时间"
     197                 value-format="yyyy-MM-dd HH:mm:ss">
     198               </el-date-picker>
     199             </el-form-item>
     200             <el-form-item label="报名结束时间:">
     201               <el-date-picker
     202                 v-model="dataForm.enterEndTime"
     203                 type="datetime"
     204                 placeholder="请选择报名结束时间"
     205                 value-format="yyyy-MM-dd HH:mm:ss">
     206               </el-date-picker>
     207             </el-form-item>
     208           </div>
     209       </FromBlock>
     210       <FromBlock :blockObj="{title:'评审设置',tip:'不填则默认没有评审流程',showBtn:true}">
     211           <div>
     212             <el-form-item label="作品评审老师:">
     213               <span v-for="(item,index) in teacherArr" :key="index" class="block-teacher">{{item.name}} 
     214                 <i class="name-delete" @click="handleDeleteTeaName(item,index)"></i> 
     215               </span>
     216               <el-button @click="openTree"> <i class="icon-small-add"></i> 添加</el-button>
     217             </el-form-item>
     218             <el-form-item label="评审截止时间:" prop="evaluateOpenTime">
     219               <el-date-picker
     220                 v-model="dataForm.evaluateOpenTime"
     221                 type="datetime"
     222                 placeholder="请选择评审截止时间"
     223                 value-format="yyyy-MM-dd HH:mm:ss">
     224               </el-date-picker>
     225             </el-form-item>
     226           </div>
     227       </FromBlock>
     228       <FromBlock :blockObj="{title:'隐私设置',tip:'',showBtn:true}">
     229           <div class="set-group">
     230               <el-checkbox v-model="dataForm.openJoin">公开报名名单</el-checkbox>
     231               <el-checkbox v-model="dataForm.openComment">打开活动评论功能</el-checkbox>
     232               <el-checkbox v-model="dataForm.openUpload">上传活动材料</el-checkbox>
     233               <el-checkbox v-model="dataForm.openPicture">照片墙</el-checkbox>
     234           </div>
     235       </FromBlock>
     236       <div class="submit-box">
     237         <el-button @click="handleCancel">取消</el-button>
     238         <el-button :disabled="submitFlag" type="primary" @click="dataFormSubmit">{{activeId?'修改':'发布'}}</el-button>
     239       </div>
     240     </el-form>
     241     <AddActivityType
     242       v-if="showAddType"
     243       @addType="addType"
     244       :showAddType='showAddType'
     245       :activityType="activityType"
     246       ref="addType"
     247     />
     248     <TeacherTree 
     249     v-if="showTree"
     250     ref="showTree"
     251     :configInfo="{title:'添加活动评审老师',treeTitle:'全体老师'}"
     252     :teacherTree="teacherTree"
     253     :checkedArr="dataForm.evaluateList"
     254     @addManage="addTeacher"/>
     255   </div>
     256 </template>
     257 
     258 <script>
     259 import FromBlock from './from-block';
     260 import AddActivityType from './add-activity-type';
     261 import { timeFormat } from '@/utils/index';
     262 import MyUpload from '@/components/common/myUpload';
     263 import TeacherTree from '@/components/common/teacher-tree';
     264 import cropper from '@/components/common/img-cropper/index';
     265 export default {
     266   name: 'creat-activity',
     267   components: {
     268     FromBlock,
     269     MyUpload,
     270     AddActivityType,
     271     TeacherTree,
     272     cropper
     273   },
     274   data() {
     275     let validateJoinNum = (rule, value, callback) => {
     276       if (value === 0) {
     277         return callback(new Error('参加人数不能为0'));
     278       } else {
     279         return callback();
     280       }
     281     };
     282     let evaluateOpenTime = (rule, value, callback) => {
     283       if (this.dataForm.evaluateList.length > 0) {
     284         if (value == '' || value == null) {
     285           return callback(new Error('请选择评审截止时间!'));
     286         } else {
     287           return callback();
     288         }
     289       } else {
     290         return callback();
     291       }
     292     };
     293     return {
     294       submitFlag: false,
     295       activeId: this.$route.query.id,
     296       dialogImageUrl: '',
     297       dialogVisible: false,
     298       showAddType: false, // 是否展示新增活动类型弹窗
     299       coverList: [],
     300       fileList: [],
     301       activityType: [],
     302       imageUrl: '',
     303       showSubmit: false,
     304       setting: {
     305         photoUrl: '',
     306         //背景图片的路径
     307         backgroundUrl: '',
     308         //图片操作区域宽度
     309          300,
     310         //图片操作区域高度
     311         height: 360,
     312         //预览框的大小及可见性
     313         target: {
     314           w: 208, // 宽度
     315           h: 117, // 高度
     316           visible: true //是否显示
     317         },
     318         //拖拽框位置
     319         cutPos: {
     320           w: 0, // 宽度
     321           h: 0, // 高度
     322           x: 0, //相对父级左边距离 大于0有效
     323           y: 0 //相对父级顶部距离 大于0有效
     324         }, // 拖拽框的范围为照片的边界,如果xy过大超出边界后,以边界值为准
     325         // 按钮样式
     326         btnStyle: {},
     327         limitSize: 0, //限制图片大小
     328         format: [] //限制图片格式
     329       },
     330       imgPosition: {
     331         x: '',
     332         y: '',
     333          '',
     334         height: ''
     335       },
     336       cutImgUrl: '',
     337       cutImgShow: false, //裁剪插件是否显示
     338       fileExt: null,
     339       dataForm: {
     340         title: '',
     341         cover: '',
     342         coverName: '',
     343         activityTime: '',
     344         beginTime: '',
     345         endTime: '',
     346         address: '',
     347         introduce: '',
     348         typeList: [],
     349         actGroup: '',
     350         joinNum: undefined,
     351         clazzList: [], //班级列表
     352         evaluateList: [], //评审教师Id数组
     353         attachmentList: [], //附件列表
     354         enterBeginTime: '', //报名开始时间
     355         enterEndTime: '', //报名结束时间
     356         evaluateOpenTime: '', //评审截止时间
     357         openJoin: false,
     358         openComment: false,
     359         openUpload: false,
     360         openPicture: false
     361       },
     362       dataRule: {
     363         title: [
     364           { required: true, message: '活动主题名称不能为空', trigger: 'blur' }
     365         ],
     366         cover: [
     367           { required: true, message: '封面图片不能为空', trigger: 'change' }
     368         ],
     369         activityTime: [
     370           { required: true, message: '活动时间不能为空', trigger: 'change' }
     371         ],
     372         typeList: [
     373           { required: true, message: '活动类型不能为空', trigger: 'change' }
     374         ],
     375         evaluateOpenTime: [
     376           {
     377             validator: evaluateOpenTime,
     378             trigger: 'change'
     379           }
     380         ],
     381         joinNum: [{ validator: validateJoinNum, trigger: 'change' }]
     382       },
     383       classTree: [],
     384       checkedKeys: [],
     385       namVal: '', //树的搜索框
     386       teacherTree: [],
     387       teacherArr: [],
     388       showTree: false,
     389       defaultProps: {
     390         children: 'child',
     391         label: 'name',
     392         value: 'id'
     393       },
     394       pickerOptions: {
     395         disabledDate(time) {
     396           // return time.getTime() > Date.now();
     397         }
     398       },
     399       tableData: [],
     400       treeChooseArr: [],
     401       groupList: [] // 分组列表
     402     };
     403   },
     404   watch: {
     405     namVal(val) {
     406       this.$refs.classTree.filter(val);
     407     }
     408   },
     409   computed: {
     410     ruleTimeFlag() {
     411       return this.dataForm.evaluateList.length > 0;
     412     }
     413   },
     414   created() {
     415     this.getActivityType();
     416     this.getClassTree();
     417     if (this.activeId) {
     418       this.getFindTreeInfo();
     419     } else {
     420       this.getTeacherTree();
     421     }
     422   },
     423   mounted() {},
     424   methods: {
     425     /* 获取班级树 */
     426     getClassTree() {
     427       this.$api['common/classTree']()
     428         .then(res => {
     429           console.log(res);
     430           let arr = [
     431             {
     432               name: '山东大学基础教育集团',
     433               id: 0,
     434               child: res['山东大学基础教育集团']
     435             }
     436           ];
     437           this.classTree = arr;
     438           console.log(this.classTree);
     439         })
     440         .catch(err => {
     441           this.$message.error(err);
     442         });
     443     },
     444     /* 获取老师树 */
     445     getTeacherTree() {
     446       let self = this;
     447       return new Promise((resolve, reject) => {
     448         this.$api['common/teacherTree']()
     449           .then(res => {
     450             console.log(res);
     451             let arr = [
     452               {
     453                 name: '山东大学基础教育集团',
     454                 id: 0,
     455                 teacherChild: res['山东大学基础教育集团']
     456               }
     457             ];
     458             console.log(arr);
     459             self.teacherTree = arr;
     460             resolve();
     461           })
     462           .catch(err => {
     463             self.$message.error(err);
     464             reject();
     465           });
     466       });
     467     },
     468     /* 获取活动类型 */
     469     getActivityType() {
     470       this.$api['activity/getType']()
     471         .then(res => {
     472           console.log(res);
     473           this.activityType = res;
     474         })
     475         .catch(err => {
     476           this.$message.error(err);
     477         });
     478     },
     479     /**
     480      * 获取活动详情
     481      */
     482     getActivityDetail() {
     483       let self = this;
     484       return new Promise((resolve, reject) => {
     485         self.$api['activity/detail']({
     486           actId: self.activeId
     487         })
     488           .then(res => {
     489             console.log(res);
     490             self.dataForm = { ...self.dataForm, ...res };
     491             self.coverList.push({
     492               url: self.dataForm.cover
     493             });
     494             res.attachmentList.forEach(item => {
     495               let temp = {
     496                 name: item.fileName,
     497                 response: item,
     498                 ...item
     499               };
     500               self.fileList.push(temp);
     501             });
     502             self.checkedKeys = res.clazzList;
     503             self.dataForm.evaluateList = res.evaluateList;
     504             self.$set(self.dataForm, 'activityTime', [
     505               self.dataForm.beginTime,
     506               self.dataForm.endTime
     507             ]);
     508             if (!self.dataForm.joinNum) {
     509               self.dataForm.joinNum = undefined;
     510             }
     511             resolve();
     512           })
     513           .catch(err => {
     514             self.$message.error(err);
     515             reject();
     516           });
     517       });
     518     },
     519     handleFileSuccess(res, file, fileList, type) {
     520       console.log(res);
     521       console.log(file);
     522       console.log(fileList);
     523       if (type === 'cover') {
     524         this.cutImgShow = true;
     525         this.cutImgUrl = res.url;
     526         this.dataForm.coverName = res.filename;
     527         this.dataForm.cover = '';
     528         this.setting.photoUrl = res.url;
     529       } else {
     530         if (fileList.length > 0) {
     531           this.dataForm.attachmentList = [];
     532           fileList.forEach(item => {
     533             let param = {
     534               fileName: item.response.filename,
     535               ...item.response
     536             };
     537             this.dataForm.attachmentList.push(param);
     538           });
     539         }
     540       }
     541 
     542       // this.imageUrl = URL.createObjectURL(file.raw);
     543       // // this.fileList.push(file);
     544       // this.dataForm.cover = this.imageUrl;
     545     },
     546     handleExceed(files, fileList) {
     547       this.$message.warning('最多可上传10个附件!');
     548     },
     549     handleFileChange(file, fileList) {
     550       console.log(file);
     551       console.log(fileList);
     552       if (fileList.length > 1) {
     553         fileList.splice(0, 1);
     554       }
     555     },
     556     handlePictureCardPreview(file) {
     557       this.dialogImageUrl = file.url;
     558       this.dialogVisible = true;
     559     },
     560     beforeAvatarUploadImg(file, fileType) {
     561       console.log(fileType);
     562       let fileTypeArr = [
     563         'png',
     564         'jpeg',
     565         'jpg',
     566         'bmp',
     567         'PNG',
     568         'JPEG',
     569         'JPG',
     570         'BMP'
     571       ];
     572       let ruleType = false;
     573       if (fileTypeArr.indexOf(fileType) != -1) {
     574         ruleType = true;
     575       } else {
     576         this.$message.error('仅可上传png/jpeg/jpg/bmp格式附件!');
     577       }
     578       let fileSize = file.size / 1024 / 1024 < 20;
     579       if (!fileSize) {
     580         this.$message.error('上传的封面图片不能超过 20MB!');
     581       }
     582       if (fileSize && ruleType) {
     583         this.fileExt = fileType;
     584       } else {
     585         this.fileExt = null;
     586       }
     587       return fileSize && ruleType;
     588     },
     589     beforeAvatarUpload(file, fileType) {
     590       let fileTypeArr = [
     591         'doc',
     592         'ppt',
     593         'docx',
     594         'pptx',
     595         'zip',
     596         '7z',
     597         'rar'
     598         // 'xls',
     599         // 'xlsx'
     600       ];
     601       let ruleType = false;
     602       if (fileTypeArr.indexOf(fileType) != -1) {
     603         ruleType = true;
     604       } else {
     605         this.$message.error('仅可上传doc/ppt/docx/pptx/zip/7z/rar格式附件!');
     606       }
     607       let fileSize = 0;
     608       if (fileType == '7z' || fileType == 'rar') {
     609         fileSize = file.size / 1024 / 1024 < 50;
     610         if (!fileSize) {
     611           this.$message.error('上传的压缩包不能超过 50MB!');
     612         }
     613       } else {
     614         fileSize = file.size / 1024 / 1024 < 10;
     615         if (!fileSize) {
     616           this.$message.error('上传的文件不能超过 10MB!');
     617         }
     618       }
     619 
     620       return fileSize && ruleType;
     621     },
     622     handleRemove(file, fileList, type) {
     623       if (type === 'cover') {
     624         this.dataForm.cover = '';
     625         this.dataForm.coverName = '';
     626       } else {
     627         if (fileList.length > 0) {
     628           this.dataForm.attachmentList = [];
     629           fileList.forEach(item => {
     630             let param = {
     631               fileName: item.response.filename,
     632               ...item.response
     633             };
     634             this.dataForm.attachmentList.push(param);
     635           });
     636         }
     637       }
     638       console.log(file, fileList);
     639     },
     640 
     641     /* 取消活动 */
     642     handleCancel() {
     643       if (this.activeId) {
     644         this.$router.go(-1);
     645       } else {
     646         this.$router.push({
     647           path: '/activityPage/managePage/manageActivity'
     648         });
     649       }
     650     },
     651     /**
     652      * 打开新增类型弹窗
     653      */
     654     openAddType(id) {
     655       let self = this;
     656       self.showAddType = true;
     657     },
     658     /**
     659      * 新增活动类型方法
     660      */
     661     addType(dataForm) {
     662       console.log(dataForm);
     663       let self = this;
     664     },
     665     /* 活动时间 change */
     666     handleActivityTime(val) {
     667       this.dataForm.beginTime = val[0];
     668       this.dataForm.endTime = val[1];
     669     },
     670     dataFormSubmit() {
     671       let self = this;
     672       console.log(this.dataForm);
     673       this.$refs.ruleForm.validate(valid => {
     674         if (valid) {
     675           this.submitFlag = true;
     676           //发送请求
     677           self.$api['activity/addOrUpdate'](this.dataForm)
     678             .then(res => {
     679               if (this.activeId) {
     680                 self.$message.success('修改成功!');
     681               } else {
     682                 self.$message.success('创建成功!');
     683               }
     684               self.$router.push({
     685                 path: '/activityPage/managePage/manageActivity'
     686               });
     687               this.submitFlag = false;
     688             })
     689             .catch(err => {
     690               this.submitFlag = false;
     691               self.$message.error(err);
     692             });
     693         } else {
     694           console.log('error submit!!');
     695           return false;
     696         }
     697       });
     698     },
     699     /* 树的过滤方法 */
     700     filterNode(value, data) {
     701       if (!value) return true;
     702       return data.name.indexOf(value) !== -1;
     703     },
     704     handleCheckChange() {
     705       let self = this;
     706       if (self.checkedKeys.length > 0) {
     707         // setTimeout(function() {}, 1000);
     708         self.handleCheck();
     709       }
     710       // this.handleCheck();
     711     },
     712     /* 班级树处理方法 */
     713     handleCheck() {
     714       let self = this;
     715       self.tableData = [];
     716       let keysTemp = [];
     717       this.dataForm.clazzList = [];
     718       keysTemp = this.$refs.classTree.getCheckedKeys(true);
     719       keysTemp.forEach(item => {
     720         console.log(self.getParent(self.classTree, item));
     721         let obj = {
     722           schoolName: '',
     723           areaName: '',
     724           grade: '',
     725           class: '',
     726           id: ''
     727         };
     728         let treeArr = self.getParent(this.classTree, item);
     729         if (treeArr.length === 4) {
     730           obj.schoolName = treeArr[0].name;
     731           obj.areaName = treeArr[1].name;
     732           obj.grade = treeArr[2].name;
     733           obj.class = treeArr[3].name;
     734           obj.id = treeArr[3].id;
     735           this.dataForm.clazzList.push(treeArr[3].id);
     736           self.tableData.push(obj);
     737         }
     738       });
     739     },
     740     /*递归 根据子元素找到父级元素  */
     741     getParent(data2, nodeId2) {
     742       var arrRes = [];
     743       if (data2.length == 0) {
     744         if (nodeId2) {
     745           arrRes.unshift(data2);
     746         }
     747         return arrRes;
     748       }
     749       let rev = (data, nodeId) => {
     750         for (var i = 0, length = data.length; i < length; i++) {
     751           let node = data[i];
     752           if (node.id == nodeId) {
     753             arrRes.unshift(node);
     754             rev(data2, node.pid);
     755             break;
     756           } else {
     757             if (node.child) {
     758               rev(node.child, nodeId);
     759             }
     760           }
     761         }
     762         return arrRes;
     763       };
     764       arrRes = rev(data2, nodeId2);
     765       return arrRes;
     766     },
     767     /* 删除管理人员 */
     768     handleDel(id, index) {
     769       this.tableData.splice(index, 1);
     770       let idIndex = this.dataForm.clazzList.indexOf(id);
     771       if (idIndex != -1) {
     772         this.dataForm.clazzList.splice(idIndex, 1);
     773       }
     774       this.$refs.classTree.setCheckedKeys(this.dataForm.clazzList);
     775       this.$message.success('删除成功');
     776     },
     777     /* 添加评审老师 */
     778     addTeacher(param) {
     779       let self = this;
     780       this.teacherArr = [];
     781       this.dataForm.evaluateList = [];
     782       if (param.length > 0) {
     783         param.forEach(item => {
     784           this.teacherArr.push({ name: item.userName, id: item.id });
     785           this.dataForm.evaluateList.push(item.id);
     786         });
     787       }
     788     },
     789     openTree() {
     790       this.showTree = true;
     791     },
     792     /* 删除评审老师 */
     793     handleDeleteTeaName(item, index) {
     794       this.teacherArr.splice(index, 1);
     795       this.dataForm.evaluateList.splice(index, 1);
     796     },
     797     getFindTreeInfo() {
     798       let self = this;
     799       Promise.all([self.getActivityDetail(), self.getTeacherTree()]).then(
     800         data => {
     801           self.getFindNode(self.teacherTree, self.dataForm.evaluateList);
     802         }
     803       );
     804       return;
     805     },
     806     /*递归 根据子元素找到父级元素  */
     807     getFindNode(data2, ids) {
     808       let self = this;
     809       if (ids.length > 0) {
     810         ids.forEach(nodeId2 => {
     811           let arrRes = {};
     812           if (data2.length == 0) {
     813             if (nodeId2) {
     814               arrRes = {};
     815             }
     816             return arrRes;
     817           }
     818           let rev = (data, nodeId) => {
     819             for (var i = 0, length = data.length; i < length; i++) {
     820               let node = data[i];
     821               if (node.id == nodeId) {
     822                 arrRes = node;
     823                 // rev(data2, node.pid);
     824                 break;
     825               } else {
     826                 if (node.teacherChild) {
     827                   rev(node.teacherChild, nodeId);
     828                 }
     829               }
     830             }
     831             return arrRes;
     832           };
     833           arrRes = rev(data2, nodeId2);
     834           let obj = { id: arrRes.id, name: arrRes.userName };
     835           self.teacherArr.push(obj);
     836           // return arrRes;
     837         });
     838       }
     839       console.log('________________________________', self.teacherArr);
     840     },
     841     keepCutImg() {
     842       this.showSubmit = true;
     843       this.$api['common/cutImage']({
     844         url: this.cutImgUrl,
     845         fileName: this.dataForm.coverName,
     846         fileExt: this.fileExt,
     847         xPoint: this.imgPosition.x,
     848         yPoint: this.imgPosition.y,
     849         hPoint: this.imgPosition.height,
     850         wPoint: this.imgPosition.width
     851       })
     852         .then(res => {
     853           this.dataForm.cover = res.fileUrl;
     854           this.dataForm.coverName = res.fileName;
     855           this.showSubmit = false;
     856           this.$refs.ruleForm.validateField('cover');
     857         })
     858         .catch(err => {
     859           this.$message.error('剪切失败了!');
     860           this.showSubmit = false;
     861         });
     862     },
     863     cancelCutImg() {
     864       this.showSubmit = false;
     865       this.cutImgShow = false;
     866       this.coverList = [];
     867       this.cutImgUrl = '';
     868       this.dataForm.cover = '';
     869       this.dataForm.coverName = '';
     870       this.setting.photoUrl = '';
     871     },
     872     /**
     873      * 获取裁剪图片区域坐标
     874      */
     875     getCutUrl(data) {
     876       this.imgPosition.x = data.left;
     877       this.imgPosition.y = data.top;
     878       this.imgPosition.height = data.height;
     879       this.imgPosition.width = data.width;
     880     }
     881   }
     882 };
     883 </script>
     884 
     885 <style scoped lang="less">
     886 .avatar-uploader .el-upload:hover {
     887   border-color: #409eff;
     888 }
     889 // .avatar-uploader-icon {
     890 //    132px;
     891 //   height: 132px;
     892 //   background-color: #f5f8fa;
     893 //   font-size: 28px;
     894 //   color: #8c939d;
     895 //   line-height: 132px;
     896 //   text-align: center;
     897 // }
     898 .avatar {
     899    132px;
     900   height: 132px;
     901   display: block;
     902 }
     903 .upload-tip {
     904   display: inline-block;
     905   padding-left: 18px;
     906   background: url('../../../../assets/images/icon-tip.png') no-repeat left 2px;
     907   margin-left: 10px;
     908   position: absolute;
     909   top: 110px;
     910   color: #999999;
     911 }
     912 .icon-set {
     913   display: inline-block;
     914    30px;
     915   height: 30px;
     916   box-sizing: border-box;
     917   position: absolute;
     918   margin-left: 10px;
     919   background: url('../../../../assets/images/icon-set.png') no-repeat center
     920     center;
     921   cursor: pointer;
     922 }
     923 /* 树结构 */
     924 .tree-box {
     925   text-align: left;
     926   .tree-left {
     927      300px;
     928     height: 370px;
     929     overflow-y: auto;
     930     border: 1px solid #e8ecf0;
     931     border-radius: 2px;
     932     box-sizing: border-box;
     933     padding: 10px;
     934   }
     935   .tree-center {
     936      50px;
     937     height: 370px;
     938     background: url('../../../../assets/images/icon-chuansuo.png') no-repeat
     939       center center;
     940   }
     941   .tree-right {
     942      550px;
     943     height: 370px;
     944     overflow-y: auto;
     945     border: 1px solid #e8ecf0;
     946     border-radius: 2px;
     947     box-sizing: border-box;
     948     padding: 10px;
     949     .icon-del {
     950       display: inline-block;
     951        16px;
     952       height: 16px;
     953       cursor: pointer;
     954       background: url('../../../../assets/images/icon-default-delete.png')
     955         no-repeat center center;
     956     }
     957     .icon-del:hover {
     958       background: url('../../../../assets/images/icon-active-delete.png')
     959         no-repeat center center;
     960     }
     961   }
     962 }
     963 
     964 /* 添加老师*/
     965 .tip-teacher-choose {
     966   display: block;
     967 }
     968 .block-teacher {
     969   display: inline-block;
     970   background-color: #f1f5f8;
     971   border-radius: 2px;
     972   height: 30px;
     973   line-height: 30px;
     974   font-size: 14px;
     975   color: #3d3e40;
     976   padding: 0 10px;
     977   margin-right: 10px;
     978   .name-delete {
     979      14px;
     980     height: 18px;
     981     background: url('../../../../assets/images/icon-delete.png') center 9px
     982       no-repeat;
     983     cursor: pointer;
     984   }
     985 }
     986 .icon-small-add {
     987    12px;
     988   height: 12px;
     989   background: url('../../../../assets/images/icon-small-add.png') center center
     990     no-repeat;
     991 }
     992 
     993 /* 隐私设置 */
     994 .set-group {
     995   text-align: left;
     996   padding-bottom: 20px;
     997 }
     998 
     999 /* 最下方的 操作按钮 */
    1000 .submit-box {
    1001   margin: 30px;
    1002 }
    1003 .file-name {
    1004    530px;
    1005 }
    1006 </style>
    1007 <style lang="less">
    1008 .create-form {
    1009   .avatar-uploader /deep/.el-upload {
    1010     border: 1px dashed #d9d9d9;
    1011     border-radius: 6px;
    1012     cursor: pointer;
    1013     position: relative;
    1014     overflow: hidden;
    1015   }
    1016   .el-input,
    1017   .el-textarea {
    1018      530px;
    1019   }
    1020   .el-input-number {
    1021     line-height: 30px;
    1022     height: 30px;
    1023   }
    1024   .el-input-number .el-input {
    1025      180px;
    1026   }
    1027   .el-input-number__decrease,
    1028   .el-input-number__increase {
    1029     height: 28px;
    1030     line-height: 28px;
    1031   }
    1032 }
    1033 .btn-wrap {
    1034   margin-top: 50px;
    1035   text-align: center;
    1036   a {
    1037     display: inline-block;
    1038     cursor: pointer;
    1039     height: 30px;
    1040     line-height: 30px;
    1041     border-radius: 2px;
    1042   }
    1043   .btn-submit {
    1044      60px;
    1045     background: #228cf9;
    1046     color: #fff;
    1047   }
    1048   .btn-submit1 {
    1049      60px;
    1050     background: #228cf9;
    1051     color: #fff;
    1052     cursor: not-allowed;
    1053   }
    1054   .btn-cancel2 {
    1055      60px;
    1056     margin-left: 12px;
    1057     border: 1px solid #228cf9;
    1058     color: #228cf9;
    1059   }
    1060 }
    1061 .cut-img-view {
    1062    160px;
    1063   height: 90px;
    1064 }
    1065 .handle-cutimg-btn {
    1066   display: inline;
    1067 }
    1068 </style>

     二.片裁剪 功能如下:



     1.createDom.js

     1 /**
     2  * @format
     3  * @description 创建dom元素
     4  * @param config 添加对象及内部元素
     5  * @param refs
     6  */
     7 
     8 function createDOM(config, refs) {
     9   if (!config) return null;
    10   var dom, childElement;
    11   if (config.tag) {
    12     dom = document.createElement(config.tag);
    13     for (var prop in config) {
    14       if (config.hasOwnProperty(prop)) {
    15         if (prop === 'content' || prop === 'tag') continue;
    16         if (prop === 'key' && refs) {
    17           var key = config[prop];
    18           if (key) {
    19             refs[key] = dom;
    20           }
    21         }
    22         dom[prop] = config[prop];
    23       }
    24     }
    25     var content = config.content;
    26     if (content instanceof Array) {
    27       for (var i = 0, j = content.length; i < j; i++) {
    28         var child = content[i];
    29         childElement = createDOM(child, refs);
    30         dom.appendChild(childElement);
    31       }
    32     } else if (typeof content === 'string') {
    33       childElement = document.createTextNode(content);
    34       dom.appendChild(childElement);
    35     }
    36   }
    37   return dom;
    38 }
    39 
    40 export default createDOM;

    2.cropper.js

      1 /** @format */
      2 
      3 import createDOM from './createDOM';
      4 import Resizer from './resize';
      5 
      6 //预加载元素
      7 var preLoadElement;
      8 
      9 //ie浏览器版本
     10 var ieVersion = Number(document.documentMode);
     11 
     12 /**
     13  * @description 获取图片大小
     14  * @param {*} src 图片路径
     15  * @param {*} callback 回调函数
     16  */
     17 function getImageSize(src, callback) {
     18   if (ieVersion < 10) {
     19     if (!preLoadElement) {
     20       preLoadElement = document.createElement('div');
     21       preLoadElement.style.position = 'absolute';
     22       preLoadElement.style.width = '1px';
     23       preLoadElement.style.height = '1px';
     24       preLoadElement.style.left = '-9999px';
     25       preLoadElement.style.top = '-9999px';
     26       //filter 用于定于元素(通常是 <img>)的可视效果。
     27       preLoadElement.style.filter =
     28         'progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=image)';
     29       document.body.insertBefore(preLoadElement, document.body.firstChild);
     30     }
     31 
     32     preLoadElement.filters.item(
     33       'DXImageTransform.Microsoft.AlphaImageLoader'
     34     ).src = src;
     35 
     36     var size = {
     37        preLoadElement.offsetWidth,
     38       height: preLoadElement.offsetHeight
     39     };
     40 
     41     if (typeof callback === 'function') {
     42       callback(size);
     43     }
     44   } else {
     45     var image = new Image();
     46     image.onload = function() {
     47       var size = {
     48          image.width,
     49         height: image.height
     50       };
     51       if (typeof callback === 'function') {
     52         callback(size);
     53       }
     54     };
     55     image.src = src;
     56   }
     57 }
     58 
     59 /**
     60  * @description 创建对象
     61  * @param {*} options 配置选项
     62  */
     63 function Cropper(options) {
     64   //实例化对象
     65   var cropper = this;
     66   if (!(this instanceof Cropper)) {
     67     cropper = new Cropper();
     68   }
     69 
     70   //对象属性拷贝
     71   for (var prop in options) {
     72     if (options.hasOwnProperty(prop)) cropper[prop] = options[prop];
     73   }
     74 
     75   if (cropper.element) {
     76     cropper.render(cropper.element);
     77   }
     78 
     79   //默认宽高比为1
     80   if (!cropper.aspectRatio) {
     81     cropper.aspectRatio = 1;
     82   }
     83 
     84   return cropper;
     85 }
     86 
     87 /**
     88  * @description 设置拖拽框大小及位置
     89  */
     90 Cropper.prototype.resetResizer = function() {
     91   //拖拽框
     92   var resizer = this.resizer;
     93   //外部框框
     94   var cropperRect = this.cropperRect;
     95   //宽高比
     96   var aspectRatio = this.aspectRatio;
     97   //宽高像素比不为数字时给一个默认值
     98   if (typeof aspectRatio !== 'number') {
     99     aspectRatio = 1;
    100   }
    101 
    102   //设定宽高,参数无效时默认值为图片的一半,超出图片区域时默认为图片的宽度
    103   var width;
    104   if (this.width > 0 && typeof this.width === 'number') {
    105     width = this.width > cropperRect.width ? cropperRect.width : this.width;
    106   } else {
    107     width = cropperRect.width / 2;
    108   }
    109   var height;
    110   if (this.height > 0 && typeof this.height === 'number') {
    111     height =
    112       this.height > cropperRect.height ? cropperRect.height : this.height;
    113   } else {
    114     height = width / aspectRatio;
    115   }
    116 
    117   //设置拖拽框的大小
    118   var resizerDom = resizer.dom;
    119   resizerDom.style.width = width + 'px';
    120   resizerDom.style.height = height + 'px';
    121 
    122   //如果配置了拖拽框的位置就按配置的来否则就居中
    123   //x
    124   if (this.x > 0 && typeof this.x === 'number') {
    125     //如果x设置超出了图片的区域则放置在图片边上
    126     if (this.x > cropperRect.width - width) {
    127       resizerDom.style.left = cropperRect.width - width + 'px';
    128     } else {
    129       resizerDom.style.left = this.x + 'px';
    130     }
    131   } else if (cropperRect) {
    132     resizerDom.style.left = (cropperRect.width - width) / 2 + 'px';
    133   } else {
    134     resizerDom.style.left = '';
    135   }
    136 
    137   //y
    138   if (this.y > 0 && typeof this.y === 'number') {
    139     //如果y设置超出了图片的区域则放置在图片底部
    140     if (this.y > cropperRect.height - height) {
    141       resizerDom.style.top = cropperRect.height - height + 'px';
    142     } else {
    143       resizerDom.style.top = this.y + 'px';
    144     }
    145   } else if (cropperRect) {
    146     resizerDom.style.top = (cropperRect.height - height) / 2 + 'px';
    147   } else {
    148     resizerDom.style.top = '';
    149   }
    150 
    151   resizer.doOnStateChange();
    152   resizer.doOnDragEnd();
    153 };
    154 
    155 //设置父级元素的图片源
    156 Cropper.prototype.setImage = function(src) {
    157   var element = this.element;
    158   var sourceImage = element.querySelector('img');
    159   var resizeImage = this.refs.image;
    160 
    161   var self = this;
    162 
    163   //图片为空时
    164   if (src === undefined || src === null) {
    165     resizeImage.src = sourceImage.src = '';
    166     resizeImage.style.width = resizeImage.style.height = resizeImage.style.left = resizeImage.style.top =
    167       '';
    168     sourceImage.style.width = sourceImage.style.height = sourceImage.style.left = sourceImage.style.top =
    169       '';
    170 
    171     //更新预览视图
    172     self.updatePreview('');
    173 
    174     self.dom.style.display = 'none';
    175     self.resetResizer();
    176 
    177     self.dom.style.left = self.dom.style.top = '';
    178     self.dom.style.width = element.offsetWidth + 'px';
    179     self.dom.style.height = element.offsetHeight + 'px';
    180 
    181     self.croppedRect = {
    182        0,
    183       height: 0,
    184       left: 0,
    185       top: 0
    186     };
    187 
    188     self.onCroppedRectChange && self.onCroppedRectChange(self.croppedRect);
    189 
    190     return;
    191   }
    192 
    193   //获取图片大小后渲染预览图
    194   getImageSize(src, function(size) {
    195     if (ieVersion < 10) {
    196       //ie9以下使用css渲染本地图片方式
    197       resizeImage.src = sourceImage.src = '';
    198       resizeImage.style.filter = sourceImage.style.filter =
    199         'progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)';
    200       sourceImage.filters.item(
    201         'DXImageTransform.Microsoft.AlphaImageLoader'
    202       ).src = src;
    203       resizeImage.filters.item(
    204         'DXImageTransform.Microsoft.AlphaImageLoader'
    205       ).src = src;
    206     } else {
    207       //其他浏览器直接复制src
    208       resizeImage.src = sourceImage.src = src;
    209     }
    210 
    211     self.imageSize = size;
    212 
    213     var elementWidth = element.offsetWidth;
    214     var elementHeight = element.offsetHeight;
    215 
    216     var dom = self.dom;
    217 
    218     var cropperRect = {};
    219     //图片大小等比缩放到父级容器的宽度之内
    220     if (size.width / size.height > elementWidth / elementHeight) {
    221       cropperRect.width = elementWidth;
    222       cropperRect.height = (elementWidth * size.height) / size.width;
    223       cropperRect.top = (elementHeight - cropperRect.height) / 2;
    224       cropperRect.left = 0;
    225     } else {
    226       cropperRect.height = elementHeight;
    227       cropperRect.width = (elementHeight * size.width) / size.height;
    228       cropperRect.top = 0;
    229       cropperRect.left = (elementWidth - cropperRect.width) / 2;
    230     }
    231 
    232     self.cropperRect = cropperRect;
    233 
    234     for (var style in cropperRect) {
    235       if (cropperRect.hasOwnProperty(style)) {
    236         dom.style[style] = sourceImage.style[style] = resizeImage.style[style] =
    237           cropperRect[style] + 'px';
    238       }
    239     }
    240 
    241     self.dom.style.display = '';
    242     self.resetResizer();
    243     self.updatePreview(src);
    244   });
    245 };
    246 
    247 //添加预览对象
    248 Cropper.prototype.addPreview = function(preview) {
    249   var previews = this.previews;
    250   if (!previews) {
    251     previews = this.previews = [];
    252   }
    253   previews.push(preview);
    254 };
    255 
    256 //渲染
    257 Cropper.prototype.render = function(container) {
    258   var resizer = new Resizer({
    259     aspectRatio: this.aspectRatio
    260   });
    261   var refs = {};
    262   //创建遮罩层
    263   var dom = createDOM(
    264     {
    265       tag: 'div',
    266       className: 'cropper',
    267       content: [
    268         {
    269           tag: 'div',
    270           className: 'mask'
    271         }
    272       ]
    273     },
    274     refs
    275   );
    276 
    277   var resizerDom = resizer.render(dom);
    278 
    279   // 创建图片区域
    280   var img = createDOM(
    281     {
    282       tag: 'div',
    283       className: 'wrapper',
    284       content: [
    285         {
    286           tag: 'img',
    287           key: 'image',
    288           src: ''
    289         }
    290       ]
    291     },
    292     refs
    293   );
    294 
    295   var self = this;
    296   self.refs = refs;
    297   //拖拽时更新预览图片
    298   resizer.doOnStateChange = function() {
    299     var left = parseInt(resizerDom.style.left, 10) || 0;
    300     var top = parseInt(resizerDom.style.top, 10) || 0;
    301 
    302     var image = refs.image;
    303 
    304     image.style.left = -left + 'px';
    305     image.style.top = -top + 'px';
    306 
    307     self.updatePreview();
    308   };
    309 
    310   resizer.doOnDragEnd = function() {
    311     var left = parseInt(resizerDom.style.left, 10) || 0;
    312     var top = parseInt(resizerDom.style.top, 10) || 0;
    313     var resizerWidth = resizerDom.offsetWidth;
    314     var resizerHeight = resizerDom.offsetHeight;
    315 
    316     var imageSize = self.imageSize;
    317     var cropperRect = self.cropperRect;
    318     //预览部分进行等比缩放
    319     if (cropperRect) {
    320       var scale = cropperRect.width / imageSize.width;
    321 
    322       self.croppedRect = {
    323          Math.floor(resizerWidth / scale),
    324         height: Math.floor(resizerHeight / scale),
    325         left: Math.floor(left / scale),
    326         top: Math.floor(top / scale)
    327       };
    328 
    329       self.onCroppedRectChange && self.onCroppedRectChange(self.croppedRect);
    330     }
    331   };
    332   self.resizer = resizer;
    333   self.dom = dom;
    334 
    335   resizerDom.insertBefore(img, resizerDom.firstChild);
    336 
    337   container.appendChild(dom);
    338 
    339   self.dom.style.display = 'none';
    340 };
    341 
    342 //更新预览图片
    343 Cropper.prototype.updatePreview = function(src) {
    344   var imageSize = this.imageSize;
    345   var cropperRect = this.cropperRect;
    346   if (!imageSize || !cropperRect) return;
    347 
    348   var previews = this.previews || [];
    349 
    350   var resizerDom = this.resizer.dom;
    351   var resizerLeft = parseInt(resizerDom.style.left, 10) || 0;
    352   var resizerTop = parseInt(resizerDom.style.top, 10) || 0;
    353 
    354   var resizerWidth = resizerDom.offsetWidth;
    355   var resizerHeight = resizerDom.offsetHeight;
    356 
    357   for (var i = 0, j = previews.length; i < j; i++) {
    358     var previewElement = previews[i];
    359     var previewImage = previewElement.querySelector('img');
    360     var previewWrapper = previewElement.querySelector('div');
    361 
    362     if (!previewImage) continue;
    363 
    364     if (src === '') {
    365       previewImage.style.width = previewImage.style.height = previewImage.style.left = previewImage.style.top =
    366         '';
    367       previewImage.src = '';
    368     } else {
    369       if (ieVersion < 10) {
    370         if (src) {
    371           previewImage.src = '';
    372           previewImage.style.filter =
    373             'progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)';
    374           previewImage.filters.item(
    375             'DXImageTransform.Microsoft.AlphaImageLoader'
    376           ).src = src;
    377           previewImage.style.width = cropperRect.width + 'px';
    378           previewImage.style.height = cropperRect.height + 'px';
    379         }
    380       } else if (src) {
    381         previewImage.src = src;
    382       }
    383 
    384       var elementWidth = previewElement.offsetWidth;
    385       var elementHeight = previewElement.offsetHeight;
    386 
    387       var scale = elementWidth / resizerWidth;
    388 
    389       if (previewWrapper) {
    390         var elementRatio = elementWidth / elementHeight;
    391         var resizerRatio = resizerWidth / resizerHeight;
    392 
    393         if (elementRatio < resizerRatio) {
    394           previewWrapper.style.width = elementWidth + 'px';
    395           previewWrapper.style.height =
    396             (resizerHeight * elementWidth) / resizerWidth + 'px';
    397           previewWrapper.style.top =
    398             (elementHeight - previewWrapper.clientHeight) / 2 + 'px';
    399           previewWrapper.style.left = '';
    400         } else {
    401           var visibleWidth = (resizerWidth * elementHeight) / resizerHeight;
    402           scale = visibleWidth / resizerWidth;
    403           previewWrapper.style.height = elementHeight + 'px';
    404           previewWrapper.style.width = visibleWidth + 'px';
    405           previewWrapper.style.left =
    406             (elementWidth - previewWrapper.clientWidth) / 2 + 'px';
    407           previewWrapper.style.top = '';
    408         }
    409       }
    410 
    411       previewImage.style.width = scale * cropperRect.width + 'px';
    412       previewImage.style.height = scale * cropperRect.height + 'px';
    413       previewImage.style.left = -resizerLeft * scale + 'px';
    414       previewImage.style.top = -resizerTop * scale + 'px';
    415     }
    416   }
    417 };
    418 
    419 export default Cropper;

    3.index.js最后输出的是这个js文件

     1 /** @format */
     2 
     3 import 'babel-polyfill';
     4 import component from './cropper.vue';
     5 
     6 export function install(Vue) {
     7   if (install.installed) return;
     8   install.installed = true;
     9   Vue.component('cropper', component);
    10 }
    11 
    12 const plugin = {
    13   install
    14 };
    15 
    16 var GlobalVue = null;
    17 if (typeof window !== 'undefined') {
    18   GlobalVue = window.Vue;
    19 } else if (typeof global !== 'undefined') {
    20   GlobalVue = global.Vue;
    21 }
    22 if (GlobalVue) {
    23   GlobalVue.use(plugin);
    24 }
    25 
    26 export default component;

    4.resize.js

      1 /** @format */
      2 
      3 'use strict';
      4 import createDOM from './createDOM';
      5 
      6 //是否正在拖拽
      7 var isDragging = false;
      8 
      9 //判断是否为ie8
     10 var isIE8 = Number(document.documentMode) < 9;
     11 
     12 //定义移动方向
     13 var configDirection = {
     14   n: {
     15     top: true,
     16     height: -1
     17   }, //
     18   w: {
     19     left: true,
     20      -1
     21   }, //
     22   e: {
     23      1
     24   }, //
     25   s: {
     26     height: 1
     27   }, //
     28   nw: {
     29     left: true,
     30     top: true,
     31      -1,
     32     height: -1
     33   }, //左下
     34   ne: {
     35     top: true,
     36      1,
     37     height: -1
     38   }, //
     39   sw: {
     40     left: true,
     41      -1,
     42     height: 1
     43   },
     44   se: {
     45      1,
     46     height: 1
     47   }
     48 };
     49 
     50 /**
     51  * @description 为元素绑定on事件
     52  * @param element 指定元素
     53  * @param event 事件名称(mouseon...)
     54  * @param fn 绑定事件
     55  */
     56 function bindEvent(element, event, fn) {
     57   //attachEvent为ie特有
     58   if (element.attachEvent) {
     59     element.attachEvent('on' + event, fn);
     60   } else {
     61     element.addEventListener(event, fn, false);
     62   }
     63 }
     64 
     65 /**
     66  * @description 为元素解除绑定on事件
     67  * @param element 指定元素
     68  * @param event 事件名称(mouseon...)
     69  * @param fn 绑定事件
     70  */
     71 function unbindEvent(element, event, fn) {
     72   //attachEvent为ie特有
     73   if (element.detachEvent) {
     74     element.detachEvent('on' + event, fn);
     75   } else {
     76     element.removeEventListener(event, fn);
     77   }
     78 }
     79 
     80 /**
     81  * @description 校正ie8浏览器钟x.y位置
     82  * @param event 事件对象
     83  */
     84 function adjustEvent(event) {
     85   var scrollTop = Math.max(
     86     window.scrollY || 0,
     87     document.documentElement.scrollTop || 0
     88   );
     89   var scrollLeft = Math.max(
     90     window.scrollX || 0,
     91     document.documentElement.scrollLeft || 0
     92   );
     93 
     94   event.target = event.srcElement;
     95   event.pageX = scrollLeft + event.clientX;
     96   event.pageY = scrollTop + event.clientY;
     97 }
     98 
     99 /**
    100  * @description 拖拽事件
    101  * @param {} element  元素
    102  * @param {*} options 元素属性
    103  */
    104 function draggable(element, options) {
    105   var moveFn = function(event) {
    106     if (isIE8) {
    107       adjustEvent(event);
    108     }
    109     if (options.drag) {
    110       options.drag(event);
    111     }
    112   };
    113   var upFn = function(event) {
    114     if (isIE8) {
    115       adjustEvent(event);
    116     }
    117     unbindEvent(document, 'mousemove', moveFn);
    118     unbindEvent(document, 'mouseup', upFn);
    119     document.onselectstart = null;
    120     document.ondragstart = null;
    121 
    122     isDragging = false;
    123 
    124     if (options.end) {
    125       options.end(event);
    126     }
    127   };
    128   bindEvent(element, 'mousedown', function(event) {
    129     if (isIE8) {
    130       adjustEvent(event);
    131     }
    132     if (isDragging) return;
    133     document.onselectstart = function() {
    134       return false;
    135     };
    136     document.ondragstart = function() {
    137       return false;
    138     };
    139 
    140     bindEvent(document, 'mousemove', moveFn);
    141     bindEvent(document, 'mouseup', upFn);
    142     isDragging = true;
    143 
    144     if (options.start) {
    145       options.start(event);
    146     }
    147   });
    148 }
    149 
    150 /**
    151  * @description 获取元素相对父元素的位置
    152  * @param {dom} element 元素对象
    153  */
    154 function getPosition(element) {
    155   var selfRect = element.getBoundingClientRect();
    156   var parentRect = element.offsetParent.getBoundingClientRect();
    157 
    158   return {
    159     left: selfRect.left - parentRect.left,
    160     top: selfRect.top - parentRect.top
    161   };
    162 }
    163 
    164 /**
    165  * @description 重新设置框框大小
    166  * @param {*} options
    167  */
    168 function Resizer(options) {
    169   for (var prop in options) {
    170     if (options.hasOwnProperty(prop)) this[prop] = options[prop];
    171   }
    172 }
    173 
    174 Resizer.prototype.doOnStateChange = function() {};
    175 
    176 Resizer.prototype.makeDraggable = function(dom) {
    177   var self = this;
    178   var dragState = {};
    179   var containment;
    180 
    181   draggable(dom, {
    182     start: function(event) {
    183       var parentNode = dom.parentNode;
    184       containment = {
    185         left: 0,
    186         top: 0,
    187          parentNode.clientWidth,
    188         height: parentNode.clientHeight,
    189         right: parentNode.clientWidth,
    190         bottom: parentNode.clientHeight
    191       };
    192 
    193       dragState.startLeft = event.clientX;
    194       dragState.startTop = event.clientY;
    195 
    196       var position = getPosition(dom);
    197 
    198       dragState.resizerStartLeft = position.left;
    199       dragState.resizerStartTop = position.top;
    200       dragState.resizerStartWidth = dom.offsetWidth;
    201       dragState.resizerStartHeight = dom.offsetHeight;
    202     },
    203     drag: function(event) {
    204       var offsetLeft = event.clientX - dragState.startLeft;
    205       var offsetTop = event.clientY - dragState.startTop;
    206 
    207       var left = dragState.resizerStartLeft + offsetLeft;
    208       var top = dragState.resizerStartTop + offsetTop;
    209 
    210       if (left < containment.left) {
    211         left = containment.left;
    212       }
    213 
    214       if (top < containment.top) {
    215         top = containment.top;
    216       }
    217 
    218       if (left + dragState.resizerStartWidth > containment.right) {
    219         left = containment.right - dragState.resizerStartWidth;
    220       }
    221 
    222       if (top + dragState.resizerStartHeight > containment.bottom) {
    223         top = containment.bottom - dragState.resizerStartHeight;
    224       }
    225 
    226       dom.style.left = left + 'px';
    227       dom.style.top = top + 'px';
    228 
    229       self.doOnStateChange();
    230     },
    231     end: function() {
    232       dragState = {};
    233       if (self.doOnDragEnd) {
    234         self.doOnDragEnd();
    235       }
    236     }
    237   });
    238 };
    239 
    240 Resizer.prototype.bindResizeEvent = function(dom) {
    241   var self = this;
    242   var resizeState = {};
    243   var aspectRatio = self.aspectRatio;
    244 
    245   if (typeof aspectRatio !== 'number') {
    246     aspectRatio = undefined;
    247   }
    248 
    249   var makeResizable = function(bar) {
    250     var type = bar.className.split(' ')[0];
    251     var transformMap = configDirection[type.substr(4)];
    252 
    253     var containment;
    254 
    255     draggable(bar, {
    256       start: function(event) {
    257         var parentNode = dom.parentNode;
    258         containment = {
    259           left: 0,
    260           top: 0,
    261            parentNode.clientWidth,
    262           height: parentNode.clientHeight,
    263           right: parentNode.clientWidth,
    264           bottom: parentNode.clientHeight
    265         };
    266 
    267         resizeState.startWidth = dom.clientWidth;
    268         resizeState.startHeight = dom.clientHeight;
    269         resizeState.startLeft = event.clientX;
    270         resizeState.startTop = event.clientY;
    271 
    272         var position = getPosition(dom);
    273         resizeState.resizerStartLeft = position.left;
    274         resizeState.resizerStartTop = position.top;
    275       },
    276       drag: function(event) {
    277         var widthRatio = transformMap.width;
    278         var heightRatio = transformMap.height;
    279 
    280         var offsetLeft = event.clientX - resizeState.startLeft;
    281         var offsetTop = event.clientY - resizeState.startTop;
    282 
    283         var width,
    284           height,
    285           minWidth = 50,
    286           maxWidth = 10000,
    287           minHeight = 50,
    288           maxHeight = 10000;
    289 
    290         if (widthRatio !== undefined) {
    291           width = resizeState.startWidth + widthRatio * offsetLeft;
    292           if (width < minWidth) {
    293             width = minWidth;
    294           }
    295 
    296           if (maxWidth && width > maxWidth) {
    297             width = maxWidth;
    298           }
    299         }
    300 
    301         if (heightRatio !== undefined) {
    302           height = resizeState.startHeight + heightRatio * offsetTop;
    303           if (height < minHeight) {
    304             height = minHeight;
    305           }
    306 
    307           if (maxHeight && height > maxHeight) {
    308             height = maxHeight;
    309           }
    310         }
    311 
    312         if (aspectRatio !== undefined) {
    313           if (type === 'ord-n' || type === 'ord-s') {
    314             width = height * aspectRatio;
    315           } else if (type === 'ord-w' || type === 'ord-e') {
    316             height = width / aspectRatio;
    317           } else {
    318             if (width / height < aspectRatio) {
    319               height = width / aspectRatio;
    320             } else {
    321               width = height * aspectRatio;
    322             }
    323           }
    324         }
    325 
    326         var position = {
    327           left: resizeState.resizerStartLeft,
    328           top: resizeState.resizerStartTop
    329         };
    330 
    331         if (transformMap.left !== undefined) {
    332           position.left =
    333             resizeState.resizerStartLeft +
    334             (width - resizeState.startWidth) * widthRatio;
    335         }
    336 
    337         if (transformMap.top !== undefined) {
    338           position.top =
    339             resizeState.resizerStartTop +
    340             (height - resizeState.startHeight) * heightRatio;
    341         }
    342 
    343         //=== containment start
    344 
    345         if (width + position.left > containment.right) {
    346           width = containment.right - position.left;
    347         }
    348 
    349         if (position.left < containment.left) {
    350           width -= containment.left - position.left;
    351           position.left = containment.left;
    352         }
    353 
    354         if (height + position.top > containment.bottom) {
    355           height = containment.bottom - position.top;
    356         }
    357 
    358         if (position.top < containment.top) {
    359           height -= containment.top - position.top;
    360           position.top = containment.top;
    361         }
    362 
    363         //=== containment end
    364 
    365         if (aspectRatio !== undefined) {
    366           if (width / height < aspectRatio) {
    367             height = width / aspectRatio;
    368           } else {
    369             width = height * aspectRatio;
    370           }
    371         }
    372 
    373         if (transformMap.left !== undefined) {
    374           position.left =
    375             resizeState.resizerStartLeft +
    376             (width - resizeState.startWidth) * widthRatio;
    377         }
    378 
    379         if (transformMap.top !== undefined) {
    380           position.top =
    381             resizeState.resizerStartTop +
    382             (height - resizeState.startHeight) * heightRatio;
    383         }
    384 
    385         dom.style.width = width + 'px';
    386         dom.style.height = height + 'px';
    387 
    388         if (position.left !== undefined) {
    389           dom.style.left = position.left + 'px';
    390         }
    391 
    392         if (position.top !== undefined) {
    393           dom.style.top = position.top + 'px';
    394         }
    395 
    396         self.doOnStateChange();
    397       },
    398       end: function() {
    399         if (self.doOnDragEnd) {
    400           self.doOnDragEnd();
    401         }
    402       }
    403     });
    404   };
    405 
    406   var bars = dom.querySelectorAll('.resize-bar');
    407   var handles = dom.querySelectorAll('.resize-handle');
    408 
    409   var i, j;
    410 
    411   for (i = 0, j = bars.length; i < j; i++) {
    412     makeResizable(bars[i]);
    413   }
    414 
    415   for (i = 0, j = handles.length; i < j; i++) {
    416     makeResizable(handles[i]);
    417   }
    418 };
    419 
    420 Resizer.prototype.render = function(container) {
    421   var self = this;
    422 
    423   var dom = createDOM({
    424     tag: 'div',
    425     className: 'resizer',
    426     content: [
    427       {
    428         tag: 'div',
    429         className: 'ord-n resize-bar'
    430       },
    431       {
    432         tag: 'div',
    433         className: 'ord-s resize-bar'
    434       },
    435       {
    436         tag: 'div',
    437         className: 'ord-w resize-bar'
    438       },
    439       {
    440         tag: 'div',
    441         className: 'ord-e resize-bar'
    442       },
    443       {
    444         tag: 'div',
    445         className: 'ord-nw resize-handle'
    446       },
    447       {
    448         tag: 'div',
    449         className: 'ord-n resize-handle'
    450       },
    451       {
    452         tag: 'div',
    453         className: 'ord-ne resize-handle'
    454       },
    455       {
    456         tag: 'div',
    457         className: 'ord-w resize-handle'
    458       },
    459       {
    460         tag: 'div',
    461         className: 'ord-e resize-handle'
    462       },
    463       {
    464         tag: 'div',
    465         className: 'ord-sw resize-handle'
    466       },
    467       {
    468         tag: 'div',
    469         className: 'ord-s resize-handle'
    470       },
    471       {
    472         tag: 'div',
    473         className: 'ord-se resize-handle'
    474       }
    475     ]
    476   });
    477 
    478   self.dom = dom;
    479 
    480   self.bindResizeEvent(dom);
    481   self.makeDraggable(dom);
    482 
    483   if (container) {
    484     container.appendChild(dom);
    485   }
    486 
    487   return dom;
    488 };
    489 
    490 export default Resizer;

    结束!!! 有能用上的麻烦点个推荐




     

     

     <!-- @format -->
  • 相关阅读:
    getRandomInt getRandomString
    git 换行符替换
    Versions maven plugin 修改版本
    spotless-maven-plugin java代码自动格式化mvn spotless:apply -fn
    eclipse.ini
    JVM架构和GC垃圾回收机制
    查看搜狗浏览器记住的密码
    TestGc finalize()
    Storm个人学习总结
    mongo嵌套查询
  • 原文地址:https://www.cnblogs.com/chenhuichao/p/13225405.html
Copyright © 2020-2023  润新知