alienzhou / web-highlighter

✨ A no-runtime dependency lib for text highlighting & persistence on any website ✨🖍️
https://alienzhou.github.io/web-highlighter/
MIT License
890 stars 144 forks source link

怎么阻止生成后双击的事件? #42

Closed CoderKwong closed 4 years ago

CoderKwong commented 4 years ago

image 如图一所示,我使用fromstore生成了高亮,但是我还是可以再次划选,导致高亮失效(图二),我应该怎样阻止这个行为?我希望的是可以不重复选区 另外,还有一个问题想请教,如何阻止click事件的响应,因为我给event.CLICK绑了事件,但是希望能自己控制在编辑状态下,click事件才响应。尝试过return,但无法阻止事件

alienzhou commented 4 years ago

重复选区的问题目前本身没有处理,如果有禁止的需求可以考虑在 Render.SelectedNodes 钩子里删除不需要高亮处理的节点。

第二个问题我理解,如果是不希望 web-highlighter 提供的 event.CLICK 事件做相应的操作,可以直接在事件绑定的代码里添加控制逻辑。如果是原生 dom 事件,目前 click 是绑定在 $root 上的,可以阻止事件冒泡上去。

CoderKwong commented 4 years ago

重复选区的问题目前本身没有处理,如果有禁止的需求可以考虑在 Render.SelectedNodes 钩子里删除不需要高亮处理的节点。

第二个问题我理解,如果是不希望 web-highlighter 提供的 event.CLICK 事件做相应的操作,可以直接在事件绑定的代码里添加控制逻辑。如果是原生 dom 事件,目前 click 是绑定在 $root 上的,可以阻止事件冒泡上去。

Render.SelectedNodes里面应该怎样处理,这个回调会循环返回ID和对应的NODE,但是我无法判断返回的元素是不是我希望保留的元素。如图一所示,希望保留的目标元素发生了class和ID的变更,属性也从data-highlight-id变成了data-highlight-extra-id

alienzhou commented 4 years ago

可以根据 selectedNodes 来获取 id,判断是否包含在同一个选区中。 如果存在这样的包含 id,则再判断一下该 id 的 wrappers 是否与当前 selectedNodes 数量一致。

目前种方式需要获取 extra-id,暂时还没有这个 API,但也可以直接从 dom 上取。后续会在新版本中加入这个 id。

这块的逻辑我可以在 example 里加一段示例。

CoderKwong commented 4 years ago

好的,麻烦您加上示例

alienzhou commented 4 years ago

Here's the example to avoid highlighting an existing selection: https://github.com/alienzhou/web-highlighter/blob/v0.6.0/example/index.js#L85-L121

code below (>= v0.6.0):

// some utils
function getIds(selected) {
    if (!selected || !selected.$node || !selected.$node.parentNode) {
        return [];
    }
    return [
        highlighter.getIdByDom(selected.$node.parentNode),
        ...highlighter.getExtraIdByDom(selected.$node.parentNode)
    ].filter(i => i)
}
function getIntersection(arrA, arrB) {
    const record = {};
    const intersection = [];
    arrA.forEach(i => record[i] = true);
    arrB.forEach(i => record[i] && intersection.push(i) && (record[i] = false));
    return intersection;
}

// use Render.SelectedNodes hook
highlighter.hooks.Render.SelectedNodes.tap((id, selectedNodes) => {
    selectedNodes = selectedNodes.filter(n => n.$node.textContent);
    if (selectedNodes.length === 0) {
        return [];
    }

    // which highlighting areas could cover current selection
    const candidates = selectedNodes.slice(1).reduce(
        (left, selected) => getIntersection(left, getIds(selected)),
        getIds(selectedNodes[0])
    );

    for (let i = 0; i < candidates.length; i++) {
        // exactly
        if (highlighter.getDoms(candidates[i]).length === selectedNodes.length) {
            return [];
        }
    }

    return selectedNodes;
});
CoderKwong commented 4 years ago

十分感谢,我先试试

CoderKwong commented 4 years ago

测试结果正常