在Vue2中实现类似Vue3中的Teleport功能

需求背景

需求:在百度地图 BMap 衍生的 BMapLib.DrawingManager(鼠标绘制工具) API 中,图形绘制完成时的确认框中加入一个时间范围选择的组件,如下:

to~

实现难点

实现难点:时间范围选择组件是Vue Element UI 组件,需要把组件渲染到 HTML 元素中,并且组件状态还得关联到当前 Vue 页面

解决方案

解决方案:将Vue组件脱离Vue组件树插入HTML中通过 组件对象 获取 组件实例,从而获取组件真实DOM 的方法。

创建组件 render(createVElement)

getVueCompHtml() {
    /** 使用创建 Vue实例 实现,Vue.extend + render 方式同理 */
    const datePicker = new Vue({
        render: h => h(DatePicker, {
            props: {
                datePickerValue: this.datePickerValue,
            },
            /** 监听事件 v-on:~ */
            on: {
                change: this.handleDatePickerChange,
            },
            nativeOn: { // 原生点击事件监听
                click: function(e) {
                    console.log('点击事件', e);
                }
            },
        })
    }).$mount(null);
    
    datePicker.$on('change', this.handleDatePickerChange);
    return datePicker.$el;
},

整体代码

当前 Vue 界面

<script>
import Vue from 'vue';
import DatePicker from "./components/DatePicker.vue"
import { getNowTime } from "@/utils";
export default {
    data() {
        const getTodayTime = () => {
            const { year, month, date, week, hour, minute, second, millisecond } = getNowTime();
            return [
                `${year}-${month}-${date} 00:00:00`,
                `${year}-${month}-${date} 23:59:59`,
            ];
        };
        return {
            map: null,
            datePickerValue: getTodayTime(), // 时间范围选择组件绑定数据
        };
    },
    methods: {
        init() {
            this.initMap(true);
        },

        /** @description: 初始化百度地图 */
        initMap(shouldInitAlarm) {
            let map = new BMap.Map("KeyRisks__map__container", {
                coordsType: 5,
                enableBizAuthLogo: false,
            }); // 创建地图实例
            let point = new BMap.Point(118.86951, 28.937343); // 创建点坐标
            map.setMaxZoom(18);
            map.centerAndZoom(point, 16); // 初始化地图,设置中心点坐标和地图级别
            map.enableScrollWheelZoom(true); // 开启鼠标滚轮缩放
            this.map = map;
            this.drawingPolygon();
        },
		// 初始化地图绘制库 BMapLib.DrawingManager
        drawingPolygon() {
            //实例化鼠标绘制工具
            this.drawingManager = new BMapLib.DrawingManager(this.map, {
                isOpen: false, //是否开启绘制模式

                completeComp: this.getVueCompHtml(), /** 将风筝组件实例传入 **/
            });  
            this.drawingManager.setDrawingMode("polygon");
        },


        // 创建组件
        getVueCompHtml() {
            const messageConstructor = Vue.extend({
                render: (h) => {
                    return h(DatePicker, {
                        props: {
                            datePickerValue: this.datePickerValue,   // 状态与当前界面同步
                            change: (e) => this.datePickerValue = e, // change
                        }, // 向组件传参
                    });
                }
            }); //生成组件的dom
            const datePicker = new messageConstructor();
            datePicker.$mount();
            return datePicker.$el;
        },
    },
};
</script>

在 DrawingManager.js 中添加~

BMapLib.DrawingManager = function (map, opts) {
    if (!map) {
        return;
    }

    instances.push(this);

    opts = opts || {};
    this.overlays = []; // 用来存储覆盖物
    // change start
    this.completeComp = opts.completeComp; // 确认设置
	// change end
    this._initialize(map, opts);
};
/	.....
	.....
	.....    /
Operate.prototype.initialize = function (map) {
    var me = this;
    this._map = map;

	// change start
    var div = this.div = document.createElement('div');
    div.className = 'operateWindow';
    
    const comp = this.DrawingManager.completeComp || '';
    div.appendChild(comp);
    var html = `<div><span id="confirmOperate">确定</span><span id="cancelOperate">取消</span></div>`;
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, "text/html");
    div.appendChild(doc.body);
	// change end

    this._map.addEventListener('resize', function (e) {
        me._adjustSize(e.size);
    });
    this._map.getPanes().markerPane.appendChild(div);
    this.updateWindow();
    this._bind();
    return div;
};

使用没毛病 over~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值