ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Vue2.x将vue文件编写的组件使用API方式动态创建(vue.extend)

2021-02-05 11:58:08  阅读:166  来源: 互联网

标签:vue extend 动态创建 height Vue markerObj 组件


文章目录

文章参考

  1. Vue.extend 看完这篇,你就学废了
  2. vue2.x挂载$mount、Vue.extend()函数的作用——由elementUI message方法联想
  3. Vue2.x 如何将vue文件编写的组件变为注册到全局组件?Vue.extend()

问题描述

  1. 在工作中使用的是Vue 脚手架搭建的,现在需要在地图上弹出一个pop 弹窗,问题是这个弹窗里面的内容全部要自己通过html写出来,因此官方给出的代码是自己写一个html字符串
let divStr = "<br/><div οnclick="myfunc()">我是弹窗显示的内容</div>",
let ele = document.createElement("div");
ele.innerHTML = divStr;
  1. 如果按照上面的写法,就需要 定义全局方法,污染全局,代码可读性降低不利于维护
  2. CSS 也需要定义全局的,不符合vue 将方法和css 放到一个组件的设计原则

解决办法

解决思路

  1. 能否用vue文件编写好组件代码,js逻辑和css全部写到vue文件中,然后创建vue组件的实例,将vue.$el 赋值给创建的div中?
  2. 如果能以这样的方式实现,就可以让js的方法作用范围在组件内部,在组件定义的css也只作用于组件,不影响全局

解决方式 Vue.extend() API

Vue.extend返回的是一个扩展实例构造器,也就是预设了部分选项的Vue实例构造器,但未曾实例化,可以理解为创建一个子类,然后让它继承Vue身上的一些功能

1. 定义好面板vue组件,将css 、js 、html 集成到一个文件中

<template>
  <div class="MapRoadPanel">
    <div class="MapRoadPanel--title">
      <span>{{markerObj.roadName}}</span>
      <span class="close h-icon-close" @click="closePanelAction"></span>
    </div>
    <div class="MapRoadPanel--content">
      <div class="MapRoadPanel--content__item">
        <div class="label">道路代码</div>
        <div class="value">{{markerObj.roadCode}} | {{markerObj.roadName}}</div>
      </div>
      <div class="MapRoadPanel--content__item">
        <div class="label">路段代码</div>
        <div class="value">{{markerObj.roadSectionCode}} | {{markerObj.roadSectionName}}</div>
      </div>
      <div class="MapRoadPanel--content__item">
        <div class="label">违禁图片</div>
        <div class="value">
          <img :src="markerObj.logoImageUrl">
        </div>
      </div>
    </div>
    <div class="MapRoadPanel--footer">
      <el-button type="primary" class="btn" @click="closePanelAction">确定</el-button>
    </div>
  </div>

</template>

<script>
export default {
  data () {
    return {
      markerObj: {
        // roadName: '长沙市南二环',
        // roadCode: '51000',
        // logoImageUrl: 'https://baidu.com/dB9I=',
        // createTime: '2021-01-29T17:11:31.849',
        // roadSectionName: '南天门',
        // roadSectionCode: '2102',
        // gpsLocation: '112.945129,28.161757',
        // dateTime: '2021-01-29 17:11:31',
        // id: '202101291711310003'
      }
    }
  },
  mounted () {},
  methods: {
    closePanelAction () {
      alert('closePanelAction')
    }
  }
}
</script>

<style lang="scss" scoped>
.MapRoadPanel {
  width: 336px;
  height: 422px;
  background: #fff;
  padding: 0 12px;
  position: relative;
  &--title {
    line-height: 40px;
    font-size: 12px;
    color: #4d4d4d;
    letter-spacing: 0;
    border-bottom: 1px solid #efefef;
    .close {
      font-size: 24px;
      position: relative;
      top: 8px;
      float: right;
      cursor: pointer;
    }
  }
  &--content {
    &__item {
      padding-top: 12px;
      .label {
        font-size: 12px;
        color: rgba(0, 0, 0, 0.4);
        letter-spacing: 0;
        line-height: 20px;
      }
      .value {
        font-size: 14px;
        color: rgba(0, 0, 0, 0.7);
        letter-spacing: 0;
        line-height: 26px;
        img {
          width: 100%;
          height: auto;
          max-height: 160px;
        }
      }
    }
  }
  &--footer {
    height: 59px;
    background-color: rgba(0, 0, 0, 0.04);
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    .btn {
      float: right;
      position: relative;
      top: 12px;
      right: 12px;
      background: #2080f7;
      width: 96px;
      height: 32px;
      color: #fff;
      line-height: 32px;
      text-align: center;
      cursor: pointer;
    }
  }
}
</style>

2. 目标组件,引用子组件,覆盖默认组件的data 和 方法

<script>
import Vue from 'vue'
import MapRoadPanel from '@/components/illegalMapConfig/MapRoadPanel'
import locationImg from '@/assets/images/icons/location.png'
import bigLocationImg from '@/assets/images/icons/bigLocation.png'
import { ajaxCtx } from '@/api/config.js'

export default {
  provide: function () {
    return {
      mapContext: this // 把当前Vue对象提供给所有子组件可以访问
    }
  },
  data () {
    // 根据定义好的视图
    const MyMapRoadPanel = Vue.extend(MapRoadPanel)
    return {
      MyMapRoadPanel, // 自定义弹窗层的组件
      locationImg,
      bigLocationImg,
      selectRoadObj: null, // 用户选中的road对象
    }
  },
  components: {
    selectConfigPanel,
    addConfigPanel
  },
  watch: {
    // 监听用户是否有选择道路
    selectRoadObj (newObj) {
      // 重新渲染图标
      this.addMarker()
      // 如果有值,则弹出详情,没有则隐藏
      if (newObj) {
        this.showSimplePopup()
      }
    }
  },
  mounted () {
    this.initMap()
  },
  methods: {
    // 返回组件的HTML
    getPanelCompHtml (markerObj, removePop) {
      const that = this
      const onePanel = new this.MyMapRoadPanel({
        data: {
          markerObj
        },
        methods: {
          closePanelAction: function () {
            that.selectRoadObj = null
          }
        }
      })
      // $mound() 方法执行之后,才会生成 $el,即创建dom 节点,视图和方法关联
      onePanel.$mount()
      return onePanel.$el
    },
    // 显示弹出层
    showSimplePopup (pointArr) {
      const ele = document.createElement('div')
      const panelDom = this.getPanelCompHtml(this.selectRoadObj, removePop)
      ele.appendChild(panelDom)
  }
}
</script>

注意:

  • 自定义组件没有注册到当前组件中,因此 自定义的组件 this ,代表的是自定义组件,而不是业务逻辑中的组件
  • 自定义组件没有注册到当前组件中,因此 this.$parent 为 undefined

标签:vue,extend,动态创建,height,Vue,markerObj,组件
来源: https://blog.csdn.net/hbiao68/article/details/113687255

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有