摘要:版本裁切工具,包含预览功能最终效果源码地址第一步先用安装脚手架不会安装的看官网初始化第二步创建文件新建里新建,在配置访问路由具体看源码最终生成的文件结构如下图第三步注册组件引用所有插件导入插件入口文件如果已安装就跳过注册插件全
vue版本裁切工具,包含预览功能
最终效果: https://qiuyaofan.github.io/vue-crop-demo/
源码地址: https://github.com/qiuyaofan/vue-crop
第一步:先用vue-cli安装脚手架(不会安装的看 vue-cli官网)// 初始化vue-cli vue init webpack my-plugin第二步:创建文件
新建src/views/validSlideDemo.vue, src/components里新建VueCrop/index.js,VueCrop.vue, 在routes/index.js配置访问路由(具体看github源码)
最终生成的文件结构如下图:
// 导入插件入口文件 import VueCrop from "./VueCrop/index.js" const install = function (Vue, opts = {}) { /* 如果已安装就跳过 */ if (install.installed) return // 注册插件 Vue.component(VueCrop.name, VueCrop) } // 全局情况下注册插件 if (typeof window !== "undefined" && window.Vue) { install(window.Vue) } export { install, // 此处是为了兼容在vue内多带带引入这个插件,如果是main.js全局引入就可以去掉 VueCrop }
import Vue from "vue" import App from "./App" import router from "./router" // 新加的:导入入口文件 import { install } from "src/components/index.js" // 全局调用,相当于调用 `MyPlugin.install(Vue)` Vue.use(install) Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: "#app", router, components: { App }, template: "" })
// 导入vue import VueCrop from "./VueCrop.vue" // Vue.js 的插件应当有一个公开方法 install 。这个方法的第一个参数是 Vue 构造器 VueCrop.install = function (Vue) { // 注册组件 Vue.component(VueCrop.name, VueCrop) } export default VueCrop
function MyPlugin(){ console.info("构造函数") } MyPlugin.prototype.install=function(vue,options){ console.info("构造器vue:"+vue); }
而真正注册组件的是:Vue.component()
所以,vue插件注册的过程是:
1.调用main.js中: import { install } from "src/components/index.js" vue.use(install) 2.index.js添加install方法,调用Vue.component注册组件 3.组件内的index.js同所有组件的index.js一样第四步:设计开发自己的组件,构建组件结构
在此之前,可以先了解下组件的命名规范等,可参考文章 掘金:Vue前端开发规范,其中第2点有详细讲解
首先,确定自己的调用方式和需要暴露的参数
>
其中,@afterCrop="afterCrop"是裁切完成的回调函数,其他是属性配置
在组件src/components/VueCrop/VueCrop.vue内,可以用this.$emit("afterCrop")触发demo里的afterCrop事件
组件结构上,主要分为:裁切主体部分(VueCrop.vue),选框组件(VueCropTool.vue),裁切框宽度、位置坐标等计算(VueCropMove.js),拖拽事件注册公共js(components/utils/draggable.js)
裁切插件的裁切主体由图片,选框,预览结构组成
选框(VueCropTool.vue)负责拖拽改变其大小,坐标位置等并返回给VueCrop.vue
主体计算数值同步预览显示(c-crop--preview)
主体触发调用页面(VueCropDemo.vue)的afterCrop事件,从而传递参数返回裁切后的url,left,top,bottom,right,x,y,w,h等
备注:此组件不具备真实的裁切功能,最终的裁切是传递给后台去裁,你如果想扩展可以在afterCrop函数里根据坐标等信息进行处理
接下来我们对各个组件和js进行讲解
export default function (element, options) { const moveFn = function (event) { if (options.drag) { options.drag(event) } } // mousedown fn const downFn = function (event) { if (options.start) { // 调用参数中start函数 options.start(event) } } // mouseup fn const upFn = function (event) { document.removeEventListener("mousemove", moveFn) document.removeEventListener("mouseup", upFn) document.onselectstart = null document.ondragstart = null if (options.end) { // 调用参数中end函数 options.end(event) } } // 绑定事件 element.addEventListener("mousedown", event => { if (options.stop && options.stop(event, element) === false) { return false } document.onselectstart = function () { return false } document.ondragstart = function () { return false } document.addEventListener("mousedown", downFn) document.addEventListener("mousemove", moveFn) document.addEventListener("mouseup", upFn) }) }
draggable(this.$el.querySelector(".c-crop--drap_screen"), { start: (event) => { this.startPos = [event.x, event.y] }, drag: (event) => { this.handleDragLocation(event) }, end: (event) => { this.handleDragLocation(event) } })
//script部分
//script部分
// 12种形态,四条边,边的中点,边的四个角。e:东,w:西,n:北,s:南,ne:东南以此类推 const movePos = { 0: e, 4: e, 1: s, 5: s, 2: w, 6: w, 3: n, 7: n, 8: ne, 9: se, 10: sw, 11: nw } let width, height, result, ratio // 获取某种形态类型的宽或高最大值 function getMaxSize (json, startJson, dire, type) { if (type === "w") { switch (dire) { case "e": case "s": case "n": case "ne": case "se": return json.screen.right - json.l case "w": case "nw": case "sw": return startJson.r - json.screen.left } } else if (type === "h") { switch (dire) { case "n": case "nw": case "ne": return startJson.b - json.screen.top case "s": case "w": case "e": case "sw": case "se": return json.screen.bottom - startJson.t } } } // 判断是否有ratio,返回修改后的尺寸 function setRatioSize (type, json, startJson, ratio, width, height) { if (ratio) { if (width / ratio >= height) { var maxHeight = getMaxSize(json, startJson, type, "h") height = width / ratio if (height > maxHeight) { height = maxHeight width = height * ratio } } else { var maxWidth = getMaxSize(json, startJson, type, "w") width = height * ratio if (width > maxWidth) { width = maxWidth height = width / ratio } } } return { width: width, height: height } } // 拖拽东边,高度是不变的,除非有比例拖拽时 function e (_this, json, startJson) { ratio = _this.cropJson.r width = range(getWidth(json, startJson, "e"), getMaxSize(json, startJson, "e", "w")) if (ratio) { // 有比例时,计算高度,并对比最大值是否超出 height = range(width / ratio, getMaxSize(json, startJson, "e", "h")) result = setRatioSize("e", json, startJson, ratio, width, height) setSize(_this, result) } else { _this.width = width } return _this } // 拖拽南边,宽度是不变的,除非有比例拖拽时 function s (_this, json, startJson) { ratio = _this.cropJson.r height = range(getHeight(json, startJson, "s"), getMaxSize(json, startJson, "s", "h")) if (ratio) { // 有比例时,计算宽度,并对比最大值是否超出 width = range(height * ratio, getMaxSize(json, startJson, "s", "w")) result = setRatioSize("s", json, startJson, ratio, width, height) setSize(_this, result) } else { _this.height = height } return _this } // 以下同上,以此类推 function w (_this, json, startJson) { ratio = _this.cropJson.r width = range(getWidth(json, startJson, "w"), getMaxSize(json, startJson, "w", "w")) if (ratio) { height = range(width / ratio, getMaxSize(json, startJson, "w", "h")) result = setRatioSize("w", json, startJson, ratio, width, height) setSize(_this, result) _this.left = getLeft(_this, json, startJson) } else { _this.width = width _this.left = rangeMax(json.x - json.screen.left, startJson.r) } return _this } function n (_this, json, startJson) { ratio = _this.cropJson.r height = range(getHeight(json, startJson, "n"), getMaxSize(json, startJson, "n", "h")) if (ratio) { width = range(height * ratio, getMaxSize(json, startJson, "n", "w")) result = setRatioSize("n", json, startJson, ratio, width, height) setSize(_this, result) _this.top = getTop(_this, json, startJson) } else { _this.height = height _this.top = rangeMax(json.y - json.screen.top, startJson.b) } return _this } function ne (_this, json, startJson) { height = range(getHeight(json, startJson, "n"), getMaxSize(json, startJson, "ne", "h")) width = range(getWidth(json, startJson, "e"), getMaxSize(json, startJson, "ne", "w")) result = setRatioSize("ne", json, startJson, _this.cropJson.r, width, height) setSize(_this, result) _this.top = getTop(_this, json, startJson) return _this } function se (_this, json, startJson) { height = range(getHeight(json, startJson, "s"), getMaxSize(json, startJson, "se", "h")) width = range(getWidth(json, startJson, "e"), getMaxSize(json, startJson, "se", "w")) result = setRatioSize("se", json, startJson, _this.cropJson.r, width, height) setSize(_this, result) return _this } function sw (_this, json, startJson) { width = range(getWidth(json, startJson, "w"), getMaxSize(json, startJson, "sw", "w")) height = range(getHeight(json, startJson, "s"), getMaxSize(json, startJson, "sw", "h")) result = setRatioSize("sw", json, startJson, _this.cropJson.r, width, height) setSize(_this, result) _this.left = getLeft(_this, json, startJson) return _this } function nw (_this, json, startJson) { width = range(getWidth(json, startJson, "w"), getMaxSize(json, startJson, "nw", "w")) height = range(getHeight(json, startJson, "n"), getMaxSize(json, startJson, "nw", "h")) result = setRatioSize("nw", json, startJson, _this.cropJson.r, width, height) setSize(_this, result) _this.left = getLeft(_this, json, startJson) _this.top = getTop(_this, json, startJson) return _this } // 匹配范围 function range (value, max) { value = value > max ? max : value return value < 20 ? 20 : value } // 最大值 function rangeMax (value, max) { return value > max ? max : value } // top function getTop (_this, json, startJson) { return rangeMax(startJson.b - _this.height - json.screen.top, startJson.b) } // left function getLeft (_this, json, startJson) { return rangeMax(startJson.r - _this.width - json.screen.left, startJson.r) } // height:只存在于s||n类型 function getHeight (json, startJson, type) { return type === "n" ? startJson.b - json.y : json.y - startJson.t } // width:只存在于w||e类型 function getWidth (json, startJson, type) { return type === "w" ? startJson.r - json.x : json.x - startJson.l } // setSize function setSize (_this, result) { _this.width = result.width _this.height = result.height } export default movePos
今天就分享到这里啦~喜欢这个插件可以去 github star~
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/94799.html
摘要:手把手教你写组件库最近在研究的实现,发现网上很少有关于插件具体实现的文章,官方的文档也只是一笔带过,对于新手来说并不算友好。 手把手教你写 Vue UI 组件库 最近在研究 muse-ui 的实现,发现网上很少有关于 vue 插件具体实现的文章,官方的文档也只是一笔带过,对于新手来说并不算友好。 笔者结合官方文档,与自己的摸索总结,以最简单的 FlexBox 组件为例子,带大家入门 v...
摘要:终极解决方案所以我们要统一环境,直接使用渲染我们的组件,文档可以参照音乐标题歌手专辑时长省去一些细节注意需要放在中,的透传也不要忘了,这样我们在外部想使用的一些属性和事件才比较方便。 背景介绍 最近在做vue高仿网易云音乐的项目,在做的过程中发现音乐表格这个组件会被非常多的地方复用,而且需求比较复杂的和灵活。 预览地址 源码地址 图片预览 歌单详情 showImg(https://se...
摘要:组件结构同组件结构通过方法获取元素的大小及其相对于视口的位置,之后对提示信息进行定位。可以用来进行一些复杂带校验的弹窗信息展示,也可以只用于简单信息的展示。可以通过属性来显示任意标题,通过属性来修改显示区域的宽度。 手把手教你撸个vue2.0弹窗组件 在开始之前需要了解一下开发vue插件的前置知识,推荐先看一下vue官网的插件介绍 预览地址 http://haogewudi.me/k...
阅读 3451·2021-09-02 09:53
阅读 1770·2021-08-26 14:13
阅读 2707·2019-08-30 15:44
阅读 1292·2019-08-30 14:03
阅读 1937·2019-08-26 13:42
阅读 2994·2019-08-26 12:21
阅读 1290·2019-08-26 11:54
阅读 1890·2019-08-26 10:46