最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Vue文件转Dom

    正文概述 掘金(奔跑的五花肉888)   2021-01-19   466

    Vue文件转成Dom方案

    问题

    开发中我们经常会遇到引入一些成熟开发库的情况,如echarts、高德地图AMap、 leaflet等等,在一些事件响应的触发上,是这些库所提供的api进行的;以高德地图为例,列举了存在的问题:

    1. 在弹窗中,仅支持拼接字符串的方式;
    2. 当需要的在弹窗的dom上绑定事件的时,无法调取当前组件的事件;
    3. 字符串中充斥着大量内联样式,可扩展性、阅读性差;
    4. 对数据的操作不清晰;

    如下代码

    
    let content = `<div>
              <div class='popup-content'>
                 <div class='content-padding'>北京市</div>
                 <div class='content-padding'>设备总数:0</div>
                 <div class='content-padding'>工厂总数:0</div>
              </div>
              <div class='info-sharp'></div>
              <a class='adcombo-close' href="javascript: void(0)" @click='closeInfoWindow()'></a>
              </div>`;
    
    

    以上代码仅仅为一个简单的例子,如果页面弹窗结构以及内容复杂可想而知开发以及修改的困难成倍增长。

    解决方法

    1. 使用Vue的extend()方法创建一个组件构造器
    2. 然后实例化创建的组件构造器
    3. 手动地挂载一个未挂载的实例
    4. 返回 Vue 实例使用的根 DOM 元素。

    实例演示

    1. 新建一个通用方法,包含以上四步骤
    // vueToDom.js
    
    import Vue from 'vue'
    export function CreateDom(obj){   // 创建一个构造函数
      const vm_obj = obj;   // 存储传入的参数对象
      function _getDomItem(){    // 定义一个转换dom方法
        const extendVM = Vue.extend(vm_obj);  // 创建一个vue构造器
        const vue_tmp = new extendVM();    // 实例化构造器
        const dom = vue_tmp.$mount().$el;  // 手动地挂载一个未挂载的实例,并获取跟元素
        return dom;
      }
      return {
        getDomItem: _getDomItem
      }
    } 
    
    
    1. 根据需求,构造自己需要的vue文件
    //  deviceInfoWindow.vue
    <template>
      <div>
        <div class="popup-content">
          <div class="content-padding">北京市</div>
          <div class="content-padding">设备总数:0</div>
          <div class="content-padding">工厂总数:0</div>
        </div>
        <div class="info-sharp"></div>
        <a
          class="adcombo-close"
          href="javascript: void(0)"
          @click="closeInfoWindow()"
        ></a>
      </div>
    </template>
    <script>
    export default {
      components: {},
      props: {
        infoWindow: {
          type: Object,
          default: () => {
            return {};
          }
        },
      },
      data() {
        return {};
      },
      created() {},
      mounted() {},
      methods: {
        closeInfoWindow() {
          this.infoWindow.close();
        },
      },
    };
    </script>
    <style scoped lang="scss">
    .popup-content {
      box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
      background: rgba(19, 18, 18, 0.7);
      border-radius: 4px;
      text-align: left;
      border: 1px solid transparent;
      // width: 100px;
      height: 100px;
      color: #fff;
    }
    .content-padding {
      padding: 15px 40px 0px 15px;
    }
    .info-sharp {
      // bottom: 0;
      left: 50%;
      margin-left: -8px;
      border-left: 8px solid transparent;
      border-right: 8px solid transparent;
      border-top: 8px solid rgba(19, 18, 18, 0.7);
      position: absolute;
    }
    .info-sharp::after {
      position: absolute;
      content: "";
      margin-left: -8px;
      margin-top: -7px;
      border-left: 8px solid transparent;
      border-right: 8px solid transparent;
      border-top: 8px solid rgba(0, 0, 0, 0.3);
      filter: blur(2px);
      z-index: -1;
    }
    .adcombo-close {
      position: absolute;
      top: 4px;
      right: 4px;
      background: url(https://webapi.amap.com/images/close.png) center center
        no-repeat;
      width: 18px;
      height: 18px;
      text-indent: -9999em;
    }
    </style>
    
    
    1. 在需要使用以上组件的vue文件中引入
    
    <template>
      <div class="device-map">
        <div class="device-content-total">
          <div class="device-total">
            <span class="content">{{ $t("deviceMap.deviceTotal") }}</span>
            <span class="number">5</span>
          </div>
          <div class="factory-total">
            <span class="content">{{ $t("deviceMap.factoryTotal") }}</span>
            <span class="number">5</span>
          </div>
        </div>
        <div class="map-content" :id="mapId"></div>
      </div>
    </template>
    
    <script>
    import { CreateDom } from "@/utils/vueToDom";
    import DeviceInfoWindow from "./deviceInfoWindow";
    export default {
      name: "DeviceMap",
      data() {
        return {
          map: null,
          mapId: "deviceMapId",
          mapPlugin: {},
          provincePolygons: [],
          infoWindow: null,
        };
      },
      created() {
      },
      mounted() {
        this.$nextTick(() => {
          this.initAmapPlugin();
          this.initAmap(this.mapId);
          this.initMapEvent(this.map);
        });
      },
      methods: {
        // 初始化地图
        initAmap(mapId) {
          this.map = new AMap.Map(mapId, {
            viewMode: "2D", // 默认使用 2D 模式,如果希望使用带有俯仰角的 3D 模式,请设置 viewMode: '3D',
            zoom: 4, //初始化地图层级
            center: [116.397428, 39.90923], //初始化地图中心点
            lang: this.$i18n.locale === "zh" ? "zh_cn" : "en",
          });
        },
        // 初始化高德地图插件
        initAmapPlugin() {
          //异步同时加载多个插件
          AMap.plugin(["AMap.Geocoder", "AMap.DistrictSearch"], () => {
            this.mapPlugin["geocoder"] = new AMap.Geocoder({ extensions: "all" });
            this.mapPlugin["districtSearch"] = new AMap.DistrictSearch({
              subdistrict: 0, //获取边界不需要返回下级行政区
              extensions: "all", //返回行政区边界坐标组等具体信息
              level: "province", //查询行政级别为 市
            });
          });
        },
        // 初始化地图事件
        initMapEvent(map) {
          map.on("click", this.getDeviveAndFactoryInfo);
        },
        // 获取当前点击事件的区域内的设备与工厂总数
        getDeviveAndFactoryInfo(e) {
          // 获取点击事件的经纬度
          let lnglat = [e.lnglat.getLng(), e.lnglat.getLat()];
          // 根据经纬度查询当前点所在的省
          this.mapPlugin.geocoder.getAddress(lnglat, (status, result) => {
            if (status === "complete" && result.regeocode) {
              let province = result.regeocode.addressComponent.province;
              this.infoWindow = new AMap.InfoWindow({
                isCustom: true,
                anchor: "bottom-center",
                closeWhenClickMap: true,
              });
              const that = this;
              //  使用组件---------------------------------------------------------------------
              const popupDom = new CreateDom({
                template: "<DeviceInfoWindow :infoWindow='infoWindow'></DeviceInfoWindow>",
                data() {
                  return { infoWindow: null };
                },
                created() {
                  // 获取当前页面的数据
                  this.infoWindow = that.infoWindow;
                },
                components: {
                  DeviceInfoWindow,
                },
              });
               //  使用组件---------------------------------------------------------------------
              this.infoWindow.setContent(popupDom.getDomItem());
              this.infoWindow.open(this.map, lnglat);
              // 根据当前省份获得当前省份的边界
              this.mapPlugin.districtSearch.search(province, (status, result) => {
                this.map.remove(this.provincePolygons); //清除上次结果
                this.provincePolygons = [];
                var bounds = result.districtList[0].boundaries;
                console.log("边界------------", bounds);
                if (bounds) {
                  for (var i = 0, l = bounds.length; i < l; i++) {
                    //生成行政区划polygon
                    var polygon = new AMap.Polygon({
                      strokeWeight: 1,
                      path: bounds[i],
                      fillOpacity: 0.4,
                      fillColor: "#80d8ff",
                      strokeColor: "#0091ea",
                    });
                    this.provincePolygons.push(polygon);
                  }
                }
                this.map.add(this.provincePolygons);
                this.map.setFitView(this.provincePolygons); //视口自适应
              });
            } else {
              this.$message.error("根据鼠标点查询省市失败");
            }
          });
        }
      },
    };
    </script>
    
    
    1. 效果图如下图

    Vue文件转Dom

    优缺点

    优点
    1. 代码逻辑统一,可阅读性强。
    2. 可拓展性、可复用性强。
    缺点
    1. 需要将项目的运行时构建更改为独立构建,性能消耗有所增加。
    2. 修改方案如下: (1)对于Vue cli3.0以上的版本 在vue.config.js文件中增加如下:
    module.exports = {
      runtimeCompiler: true,
    }
    

    (2)对于以下版本修改如下代码:

    module.exports = {
    // ...
    resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
    'vue$': 'vue/dist/vue.esm.js', // runtime-only版本为'vue/dist/vue.runtime.esm.js'
    '@': resolve('src')
    }
    },
    

    总结

    如果该篇文章对您有帮助,请帮忙点个赞,谢谢~~~~


    起源地下载网 » Vue文件转Dom

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元