代码仓库:http://gitlab.prod.dtstack.cn/visdev/visApplication/easyvc_new/draw-9-patch.git
先来看看EasyV中点九图组件的编辑效果:
从上图中可以看出一下几个功能点:
1.组件进入编辑模式后,会出现四根绿色的线(edit属性)。
2.鼠标拖动四根绿线,图片会做出相应的缩放变化(点九图特性,不懂的自行百度,该功能的实现不是本文重点)。
3.鼠标抬起后左侧的配置项也会发生对应的改变(updateConfig函数)。
4.同时,修改右侧的配置项,也会引起绿线的位置发生变化以及图片产生缩放。
1.updateConfig函数,组件props中的一个属性,该函数可以通过代码修改组件的配置项,流程如下:
2.edit属性,组件props中的一个Boolean类型的属性,该属性用于声明用户当前是否在编辑模式中(true为是,false为否),注意,编辑模式不等于编辑页面,编辑页面中组件的各种鼠标事件是失效的,而编辑模式中是有效的。
3.点九图,将dom的border-image-source设置为对应的图片地址,调整border-image-slice的值即可实现切割图片并缩放的效果。
1.对于功能点1,这其实很好实现,我们可以从props里拿到edit属性,根据edit的值来显隐四根绿线即可。
2.从功能点2中可以看出,我们需要给四根绿线添加鼠标事件,并达到拖动的效果。最简单粗暴的方法就是通过鼠标移动事件来修改四根绿线的偏移值,不过结合我们整体的需求来看,我们知道绿线的偏移并不是只受鼠标控制的,同时还会被config所影响,所以我们可以用useState来记录四根绿线的偏移值,将其保存为一种状态(代码库中我用的是useReducer,效果其实是差不多的)。
const [states, dispatch] = useReducer((state,action)=>{
const { type, value } = action;
if(type=="reset"){ //当config变化时将config设置为偏移值
return value;
}else if(type=="update"){ //当鼠标抬起时,执行updateConfig来更新偏移值配置项
const direction = action.direction; //根据action传过来的direction来决定修改哪根绿线的值
let values = [state[value],state[(value+2)%4]];
//这里需要验证一下values数组是否是递增的,否则就交换元素位置,保证递增
values = values[0]>values[1]?[values[1],values[0]]:values;
//执行updateConfig来告诉服务器需要修改组件配置项
updateConfig && updateConfig({
type:"config",
payload:{
path:["editProps",direction],
value:values
}
});
//直接返回上一个state
return state;
}else{ //默认情况为拖动绿线修改了偏移值
const ranges = action.ranges; //ranges
let newValue = state[type]+value;
return [...state.slice(0,type), Math.min(Math.max(newValue, ranges[0]), ranges[1]), ...state.slice(type+1)];
}
},[horizontal[0], vertical[1], horizontal[1], vertical[0]]); //分别是上、右、下、左四根绿线的偏移值,和CSS规则一样
//这里监听偏移值配置项,vertival和horizontal分别表示垂直和水平偏移的值。
useEffect(()=>{
dispatch({
type:"reset",
value:[horizontal[0],vertical[1],horizontal[1],vertical[0]]
})
},[JSON.stringify(horizontal), JSON.stringify(vertical)]);
上面的代码有个地方需要注意,在调用完updateConfig后,我直接return state;这个state是前一次的状态,说明这里我压根没有改变state中的绿线偏移值,这是为什么呢?因为updateConfig会在服务器返回结果后,更新一次config,会直接触发useEffect中的代码来执行reset动作,所以我压根不需要提前设置state。
3.然后我们来完成鼠标拖动改变绿线位置的功能,这里我们只需给绿线dom添加一个mousedown事件即可,然后把mousemove和mouseup绑定到document上,这样可以避免鼠标滑出绿线时事件失效的bug。在鼠标抬起时记得移除对应的监听事件,避免内存泄漏。
const down=()=>{
const move = (e)=>{
context.dispatch({
type:index,
value:(isHorizontal?e.movementY:e.movementX)/5, //这个5是为了减速用的
ranges //[51,100] || [0,49],[0,49]表示左侧或上侧的线,[51,100]相反。
})
}
const up=()=>{
context.dispatch({
type:"update",
value:index,
direction
});
document.removeEventListener("mousemove",move);
document.removeEventListener("mouseup",up);
}
document.addEventListener("mousemove",move);
document.addEventListener("mouseup",up);
}
为什么我们需要在mouseup的时候updateConfig,而不是在mousemove的时候执行updateConfig呢?因为mousemove的触发频率太高了,频繁的更新是毫无意义且浪费性能的,另外,从updateConfig的更新流程中也可以看出,updateConfig需要进行一次http请求,大量发送http请求必然会导致其执行顺序发生紊乱,其结果就是updateConfig几乎失效。
4.对于功能点4,这是一个非常常规的需求,根据config来调整组件的样式,是日常组件开发中经常会遇到的需求。其实,我们在第二点中就已经实现了这个功能,没错,就是那个useEffect,我们通过useEffect对config进行依赖,以此来修改绿线的偏移值,完成了这个功能。
在编辑模式中,实现这种 交互和配置项 双向绑定的功能是非常有用的,可以帮助用户减少不必要的操作,自由调整想要的效果,所以,我们必须要理解这种双向绑定的实现逻辑,并能够运用。
文章
10.49W+人气
19粉丝
1关注
©Copyrights 2016-2022 杭州易知微科技有限公司 浙ICP备2021017017号-3 浙公网安备33011002011932号
互联网信息服务业务 合字B2-20220090