爬蟲可視化點選配置工具之獲取鼠標點選元素

前言

前面兩章已經介紹怎麼開發一個chrome插件和怎麼使用vue搭建一個彈出框的chrome插件,這一章來實現頁面元素選擇的功能,效果如下圖,鼠標放到元素上,元素會高亮:

clipboard.png

主要實現思路,創建一個和頁面一樣寬高的蒙層,監聽蒙層的鼠標移動事件,再使用elementFromPoint函數來獲得當前鼠標所在位置的頁面元素,具體實現如下:
shelter.js這是主函數

import $ from 'jquery';
import validateSelect from './validateSelected';
import isContentElement from "./isContentElement";

//選擇遮罩
export default class {
    constructor() {
        this.shelter = $("<div class='layuiex'></div>"); //選擇過程中的div
        this.shelter.attr("id", "__pAp_SpiderShelter");

        this.block = $("<div class='layuiex'></div>");

        this.lastSelectEl = null; //當前鼠標移動到元素
        this.shelterInterval = null;

        $(document.body).append(this.shelter);
        $(document.body).append(this.block);
    }

    beginSelect(onDomClick, onContextMenu, callback) {
        let that = this;
        this.shelter.css("position", "absolute");
        this.shelter.css("display", "block");
        this.shelter.addClass("pAp_spider_Selecter_Block");
        this.shelter.bind("click", onDomClick);
        this.shelter.show();
        this.shelter.css("width", "100%");
        this.shelter.css("height", $(document).height() + "px");
        this.shelter.css("left", "0");
        this.shelter.css("top", "0");
        this.shelter.mousemove(this.onShelterMouseMove(callback));
        //初始化遮罩
        function initCover() {
            that.shelterInterval = setInterval(function() {
                //如果遮罩層的高度小於頁面高度,則將遮罩的高度設置成頁面高度
                if ($(document).height() > that.shelter.height()) {
                    that.hideCover();
                    that.showCover();
                }
            }, 500);
        }

        //鼠標移動到遮罩層上的時候,重置遮罩層
        this.shelter.mouseover(function() {
            if (that.shelterInterval) {
                clearInterval(that.shelterInterval);
                that.shelterInterval = null;
            }
        }).mouseout(initCover);

        this.block.css("position", "absolute");
        this.block.css("display", "block");
        this.block.show();
        this.showShelter(); //顯示遮罩陰影
        this.block.css("z-index", "19891009")
        this.shelter.css("z-index", "19891010");

        //綁定右鍵事件
        document.oncontextmenu = onContextMenu;

        //鼠標滾動事件,目的是防止頁面滾動
        $(this.shelter).on("mousewheel", function(evt) {
            event.stopPropagation();
            event.preventDefault();
            var height = evt.originalEvent.wheelDelta;
            if (!that.lastSelectEl) return;
            var el = that.lastSelectEl.get(0);
            while (el) {
                if (el.scrollHeight > el.offsetHeight || el.tagName == "BODY") {
                    var lastTop = el.scrollTop;
                    el.scrollTop = el.scrollTop - height;
                    if (lastTop !== el.scrollTop) {
                        break;
                    }
                }
                el = el.parentElement;
            }
        });
        initCover();
    };

    endSelect(callback) {
        if (this.shelterInterval) {
            clearInterval(this.shelterInterval);
            this.shelterInterval = null;
        }
        this.shelter.unbind();
        this.shelter.remove();
        this.block.remove();
        $(document).unbind();
        document.oncontextmenu = function() {};
        callback && callback();
    };

    showShelter() {
        this.block.css("box-shadow", "0 0 20px #d4930d");
    };

    hideShelter() {
        this.block.css("box-shadow", "none");
    };

    //鼠標移動時的操作
    onShelterMouseMove(callback) {
        let that = this;
        var position = {
            x: 0,
            y: 0
        };

        return function(e) {
            event.stopPropagation();
            if (Math.abs(position.x - e.pageX) > 10 || Math.abs(position.y - e.pageY) > 10) {
                //隱藏蒙層
                that.hideCover();
                //返回當前鼠標所在位置的最頂層元素,也就是鼠標所在的頁面元素
                var el = $(document.elementFromPoint(e.clientX, e.clientY));
                //顯示蒙層
                that.showCover();

                //如果是彈出框或者是遮罩則返回
                if (!isContentElement(el)) return;

                //如果元素中有我們生成的屬性,則取父元素
                if (!validateSelect(el)) {
                    el = el.parent();
                }
                if (!that.lastSelectEl || that.lastSelectEl.get(0) != el.get(0)) {
                    that.lastSelectEl = el;
                }
                position = {
                    x: e.pageX,
                    y: e.pageY
                };
                that.setPosition(el, that.block);
                callback && callback(that.lastSelectEl);
            }
        }
    }

    setShelterPosition(el) {
        this.setPosition(el, this.shelter);
    }

    /**
     * 把選擇框設置噹噹前選擇元素的位置
     * @param {Jquery Dom Element} el 選擇的元素
     * @param {Jquery Dom Element} shelter 遮罩層
     */
    setPosition(el, shelter) {
        if ((el.width() == 0 || el.height() == 0) && el.get(0).tagName == 'A' && el.children().length) {
            that.setPosition(el.children().eq(0), shelter);
            return;
        }

        var paddingObject = {
            left: parseInt(el.css("padding-left")),
            top: parseInt(el.css("padding-top")),
            right: parseInt(el.css("padding-right")),
            bottom: parseInt(el.css("padding-bottom"))
        };

        var _width = 0,
            _height = 0;
        if (!isNaN(paddingObject.left)) {
            _width += paddingObject.left;
        }
        if (!isNaN(paddingObject.right)) {
            _width += paddingObject.right;
        }
        if (!isNaN(paddingObject.top)) {
            _height += paddingObject.top;
        }
        if (!isNaN(paddingObject.bottom)) {
            _height += paddingObject.bottom;
        }

        var top = parseInt(el.offset().top);
        var height = el.height() + _height;
        var availHeight = $(document).height() - top;
        height = height > availHeight ? availHeight : height;

        var obj = {
            "left": parseInt(el.offset().left) + "px",
            "top": top + "px",
            "width": el.width() + _width,
            "height": height
        };

        shelter.css(obj);
    };

    hideCover() {
        this.block.css("z-index", "-2")
        this.shelter.css("z-index", "-1");
        this.shelter.css("display", "none");
        this.block.css("display", "none");
    };

    showCover() {
        this.shelter.css("display", "block");
        this.block.css("display", "block");
        this.block.css("z-index", "19891009")
        this.shelter.css("z-index", "19891010");

        var height = $(document).height();
        this.shelter.css("width", "100%");
        this.shelter.css("height", height + "px");
        this.shelter.css("left", "0");
        this.shelter.css("top", "0");
    };

    setBlockCss(key, value) {
        this.block.css(key, value);
    }

    setShelterCss(key, value) {
        this.shelter.css(key, value);
    }
}

validateSelected.js確保所選擇的元素是頁面本身的元素

import $ from 'jquery';

/**
 * 判斷是否有我們生成的元素,即被我們標記爲選中的元素
 * @param {*} element 
 */
export default function(element) {
    var el = $(element);

    if (el.attr("__pAp_select")) {
        return false;
    }

    if (el.hasClass("__pAp_selectrow")) {
        return false;
    }
    return true;
};

isContentElement.js這個函數的作用也是確保所選擇的的元素是頁面自有的元素

import $ from 'jquery';

/*
    判斷是否內容元素,也就是判斷是不是我們的彈出框或者是遮罩
*/
export default function(element) {
    var expectClasses = [".layuiex", ".layuiex-layer", ".layuiex-layer-shade", ".layuiex-layer-moves", ".pAp_spider_Selecter_Block"];
    for (var _i = 0; _i < expectClasses.length; _i++) {
        var els = $(expectClasses[_i]);
        for (var a = 0; a < els.length; a++) {
            //$.contains( container, contained )
            //檢測一個元素包含在另一個元素之內
            //container    Element類型 指定可能包含其他元素的祖輩容器元素。
            //contained    Element類型 指定可能被其他元素包含的後代元素。
            if ($.contains(els.eq(a).get(0), element) || els.eq(a).get(0) == element) {
                return false;
            }
        }
    }
    return true;
};

這樣頁面選擇函數就寫完了,下面就是引用了,在main.js中添加函數

import Vue from 'vue';
import $ from "jquery";
import './layer/layer.css';
import layer from './layer/layer';
import shelter from './js/selector/shelter';

Vue.config.productionTip = false;
let shelterUi = new shelter();

......

new Vue({
    el: "#__paApa_container",
    components: {},
    data() {
        return {
            selectedEl: null
        };
    },
    mounted() {
        let that = this;
        shelterUi.beginSelect(that.onDomClick, null,
            function(selectedEl) {
                that.selectedEl = selectedEl;
            });
    },
    methods: {
        onDomClick() {
            console.log('點擊');
        }
    }
});

以上就完成了頁面選擇功能

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章