Popover.js 8.32 KB
import template from "./Popover.html";
import style from "antd/lib/popover/style/index.css";
angular
    .module("esNgAntd")
    .directive("esPopover", function ($compile, $timeout, esNgAntd) {
        return {
            controllerAs: "esPopover",
            restrict: "E",
            transclude: true,
            replace: true,
            scope: {
                title: "@",
                content: "@",
                context: "=",
                placement: "@",
                getPopupContainer: "&",
                trigger: "@",
            },
            template: template,
            controller: function ($scope, $element, $attrs) {
                this.getContext = function () {
                    return $scope;
                };

                $scope.state = {
                    visible: false,
                    content: $scope.content ? $scope.content : "",
                    clickTarget: null,
                    trigger: $scope.trigger || "hover",
                    closing: false,
                };

                $scope.myEvent = function () {
                    setTimeout(() => {
                        $scope.state.visible = false;
                        $scope.$apply();
                        document.body.removeEventListener(
                            "click",
                            $scope.myEvent
                        );
                    }, 0);
                };

                $scope.handleClick = function () {
                    if ($scope.state.trigger !== "click") {
                        return;
                    }

                    if ($scope.state.visible === false) {
                        // 气泡层(显示)
                        $scope.state.visible = true; // 处理位置

                        $scope.handlePosition(); // 事件绑定

                        document.body.addEventListener("click", $scope.myEvent);
                    } else {
                        setTimeout(() => {
                            $scope.state.visible = false;
                            $scope.$apply();
                            document.body.removeEventListener(
                                "click",
                                $scope.myEvent
                            );
                        }, 0);
                    }
                };

                $scope.showPopover = function () {
                    // 气泡层(显示)
                    $scope.state.visible = true; // 调整位置

                    $scope.handlePosition();
                };

                $scope.hidePopover = function () {
                    $scope.state.closing = true;
                    $timeout(function () {
                        if ($scope.state.closing === false) {
                            return;
                        }

                        $scope.state.visible = false;
                    }, 100);
                };

                $scope.onMouseEnter = function () {
                    if ($scope.state.trigger !== "hover") {
                        return;
                    }

                    if ($scope.state.closing === true) {
                        $scope.state.closing = false;
                    }

                    $scope.showPopover();
                };

                $scope.onMouseLeave = function () {
                    if ($scope.state.trigger !== "hover") {
                        return;
                    }

                    $scope.hidePopover();
                };

                $scope.handlePosition = function () {
                    setTimeout(function () {
                        let popover =
                            $scope.state.popover.querySelector(".ant-popover");

                        if ($scope.placement === "top") {
                            popover.style["top"] = $scope.getTop();
                        } else if ($scope.placement === "bottom") {
                            popover.style["top"] = $scope.getTop();
                        }

                        popover.style.left = $scope.getLeft() + "px";
                    }, 0);
                };

                $scope.getLeft = function () {
                    let parent = $scope.getPopupContainer();
                    let popover =
                        $scope.state.popover.querySelector(".ant-popover");
                    let target = $scope.state.target;

                    if (parent) {
                        return -(
                            popover.clientWidth / 2 -
                            target.clientWidth / 2
                        );
                    } else {
                        let offset = esNgAntd.getOffset(target);
                        return (
                            offset.left -
                            (popover.clientWidth / 2 - target.clientWidth / 2)
                        );
                    }
                };

                $scope.getTop = function () {
                    let parent = $scope.getPopupContainer();
                    let popover =
                        $scope.state.popover.querySelector(".ant-popover");
                    let target = $scope.state.target;

                    if (parent) {
                        if ($scope.placement === "top") {
                            return -popover.clientHeight + "px";
                        } else if ($scope.placement === "bottom") {
                        }
                    } else {
                        let offset = esNgAntd.getOffset(target);

                        if ($scope.placement === "top") {
                            return offset.top - popover.clientHeight - 4 + "px";
                        } else if ($scope.placement === "bottom") {
                            return offset.top + target.clientHeight + 4 + "px";
                        }
                    }
                };
            },
            link: function (
                $scope,
                $element,
                $attrs,
                $controllers,
                $transclude
            ) {
                esNgAntd.createStyle("ant-popover", style);
                $scope.state.target = $element[0];
                let title = $scope.title
                    ? `<div class="ant-popover-title"><span>${$scope.title}</span></div>`
                    : "";
                let content = `<div>
            <div style="outline:none" ng-class="'ant-popover ant-popover-placement-${$scope.placement}'+(!state.visible?' ant-popover-hidden': '')+(state.visible?' ant-zoom-big-enter ant-zoom-big-enter-active': '')" ng-mouseleave="onMouseLeave()" ng-mouseenter="onMouseEnter()">
                <div class="ant-popover-content">
                    <div class="ant-popover-arrow">
                        <span class="ant-popover-arrow-content"></span>
                    </div>
                    <div class="ant-popover-inner">
                        <div>
                            ${title}
                            <div class="ant-popover-inner-content"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>`;
                let div = document.createElement("div");

                if (typeof $scope.getPopupContainer() === "function") {
                    $scope.state.popupContainer = $scope.getPopupContainer()();
                }

                if (!$scope.state.popupContainer) {
                    div.style.position = "absolute";
                    div.style.top = "0px";
                    div.style.left = "0px";
                    div.style.width = "100%";
                    div.innerHTML = content;
                    document.body.appendChild(div);
                } else {
                    $scope.state.popupContainer.appendChild(div);
                }

                div.addEventListener("click", function (event) {
                    event.stopPropagation();
                });
                $scope.state.target.addEventListener("click", (e) => {
                    e.stopPropagation();
                });
                $compile(div)($scope);
                div.querySelector(".ant-popover-inner-content").innerHTML =
                    $scope.state.content;
                $compile(div.querySelector(".ant-popover-inner-content"))(
                    $scope.$parent
                );
                $scope.state.popover = div;
            },
        };
    });