提问 发文

从点九图看EasyV编辑模式的使用方式

微微菌

| 2024-02-06 17:22 99 0 0

代码仓库: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进行依赖,以此来修改绿线的偏移值,完成了这个功能。

结尾:

在编辑模式中,实现这种 交互和配置项 双向绑定的功能是非常有用的,可以帮助用户减少不必要的操作,自由调整想要的效果,所以,我们必须要理解这种双向绑定的实现逻辑,并能够运用。

收藏 0
分享
分享方式
微信

评论

游客

全部 0条评论

8910

文章

4.27W+

人气

11

粉丝

1

关注

官方媒体

轻松设计高效搭建,减少3倍设计改稿与开发运维工作量

开始免费试用 预约演示

扫一扫关注公众号 扫一扫联系客服

©Copyrights 2016-2022 杭州易知微科技有限公司 浙ICP备2021017017号-3 浙公网安备33011002011932号

互联网信息服务业务 合字B2-20220090

400-8505-905 复制
免费试用
微信社区
易知微-数据可视化
微信扫一扫入群