基于elementUI的一个使用v-model实现的经纬度输入的vue组件

栏目: JavaScript · 发布时间: 6年前

内容简介:一个span显示东经西经,三个输入框输入度分秒修改子组件值 父组件的value会改变,修改父组件的value,子组件会自动修改, [change value] 按钮 可以修改value [refresh] 按钮 通过ref获取度分秒格式的经纬度
  • 绑定一个 [12.34,-45.67] (东经西经,南纬北纬 正负表示) 形式的经纬度数组,能够按度分秒进行编辑,效果如下所示,点击东经,北纬可切换。
  • 经纬度的 度转度分秒
  • 能够获取度分秒格式数据
基于elementUI的一个使用v-model实现的经纬度输入的vue组件

Coordinates组件实现

  • 模板

一个span显示东经西经,三个输入框输入度分秒

<template>
  <div class="coordinates">
    <!-- 经度 -->
    <div class="item">
      <span class="itude"
            @click="itudeChange(true)">{{ longFlag | longitudeName }}</span>
      <el-input v-model.number="longitude[0]"
                @change="change(true,0)"
                size="mini">
        <i slot="suffix">°</i>
      </el-input>
      <el-input v-model.number="longitude[1]"
                @change="change(true,1)"
                size="mini">
        <i slot="suffix">′</i>
      </el-input>
      <el-input v-model.number="longitude[2]"
                @change="change(true,2)"
                size="mini">
        <i slot="suffix">″</i>
      </el-input>
    </div>
    <!-- 纬度 -->
    <div class="item">
      <span class="itude"
            @click="itudeChange(false)">{{ latFlag | latitudeName }}</span>
      <el-input v-model.number="latitude[0]"
                @change="change(false,0)"
                size="mini">
        <i slot="suffix">°</i>
      </el-input>
      <el-input v-model.number="latitude[1]"
                @change="change(false,1)"
                size="mini">
        <i slot="suffix">′</i>
      </el-input>
      <el-input v-model.number="latitude[2]"
                @change="change(false,2)"
                size="mini">
        <i slot="suffix">″</i>
      </el-input>
    </div>
  </div>
</template>
复制代码
  • 实现
  1. props: 父组件传入的参数 value ,验证合法性 经度绝对值小于180,纬度绝对值小于90,数组长度为2
value: { //绑定的 value
  type: Array,
  require: true,
  validator: function (value) {
    let len = value.length > 0 && value.length === 2
    let isvalid = Math.abs(value[0]) < 180 && Math.abs(value[1]) < 90
    return len && isvalid
  },
  default: function () {
    return []
  }
}
复制代码
  1. model: prop为 value 时不用实现 model 但是this.$emit(event,arg) 传入的event需要为 'input',这里要注意
model: {  
  prop: 'value',
  event: 'input'
},
复制代码
  1. v-model实现: 使用this.$emit(event,arg)修改父组件的数据
/**
 * v-model 绑定事件  双向绑定实现
 */
returnBackFn () {
  let longitude = parseFloat(this.longFlag + this.Dms2D(this.longitude));
  let latitude = parseFloat(this.latFlag + this.Dms2D(this.latitude));
  let array = [longitude, latitude]
  this.$emit('input', array);
},
复制代码

Coordinates组件完整代码

<template>
  <div class="coordinates">
    <!-- 经度 -->
    <div class="item">
      <span class="itude"
            @click="itudeChange(true)">{{ longFlag | longitudeName }}</span>
      <el-input v-model.number="longitude[0]"
                @change="change(true,0)"
                size="mini">
        <i slot="suffix">°</i>
      </el-input>
      <el-input v-model.number="longitude[1]"
                @change="change(true,1)"
                size="mini">
        <i slot="suffix">′</i>
      </el-input>
      <el-input v-model.number="longitude[2]"
                @change="change(true,2)"
                size="mini">
        <i slot="suffix">″</i>
      </el-input>
    </div>
    <!-- 纬度 -->
    <div class="item">
      <span class="itude"
            @click="itudeChange(false)">{{ latFlag | latitudeName }}</span>
      <el-input v-model.number="latitude[0]"
                @change="change(false,0)"
                size="mini">
        <i slot="suffix">°</i>
      </el-input>
      <el-input v-model.number="latitude[1]"
                @change="change(false,1)"
                size="mini">
        <i slot="suffix">′</i>
      </el-input>
      <el-input v-model.number="latitude[2]"
                @change="change(false,2)"
                size="mini">
        <i slot="suffix">″</i>
      </el-input>
    </div>
  </div>
</template>


<script>

require('math')
export default {
  name: 'Coordinates',
  props: {
    value: { //绑定的 value
      type: Array,
      require: true,
      validator: function (value) {
        let len = value.length > 0 && value.length === 2
        let isvalid = Math.abs(value[0]) < 180 && Math.abs(value[1]) < 90
        return len && isvalid
      },
      default: function () {
        return []
      }
    }
  },
  // model: {  // prop为 value 时不用实现 model 但是this.$emit(event,arg) 传入的event需要为 'input'
  //   prop: 'value',
  //   event: 'returnBack'
  // },
  data () {
    return {
      longitude: [],  // 经度
      latitude: [],   // 纬度
      longFlag: '+',  //表示东经西经
      latFlag: '+',   //表示南纬北纬
    }
  },
  created: function () {
    this.initData();
  },
  filters: {
    longitudeName (value) {
      return value === '+' ? "东经" : "西经"
    },
    latitudeName (value) {
      return value === '+' ? "南纬" : "北纬"
    }
  },
  watch: {
    /**
    * 监测父组件绑定的value
    */
    value () {
      this.initData();
    }
  },
  computed: {
    // 转换为    东经 XXX°XX′XX″   格式 
    // 返回一个经纬度的数组
    formatString () {
      let longitude = (this.longFlag === '+' ? "东经 " : "西经 ") + this.longitude[0] + '°' + this.longitude[1] + '′' + this.longitude[2] + '″';
      let latitude = (this.latFlag === '+' ? "南纬 " : "北纬 ") + this.latitude[0] + '°' + this.latitude[1] + '′' + this.latitude[2] + '″';
      return [longitude, latitude]
    }
  },
  methods: {
    /**
     * 东经西经,南纬北纬 change事件
     */
    itudeChange (flag) {
      flag ? (this.longFlag = (this.longFlag === '+' ? '-' : '+')) : (this.latFlag = (this.latFlag === '+' ? '-' : '+'))
      this.returnBackFn()
    },

    /**
     * 初始化数据,父组件修改绑定的value时调用
     */
    initData () {
      this.longitude = this.D2Dms(Math.abs(this.value[0]));
      this.latitude = this.D2Dms(Math.abs(this.value[1]));
      this.longFlag = this.value[0] < 0 ? '-' : '+'
      this.latFlag = this.value[1] < 0 ? '-' : '+'
    },

    /**
     * 输入框change事件,数据合法性验证
     */
    change (flag, index) {
      let name = '', max = 0
      flag ? [name, max] = ['longitude', 179] : [name, max] = ['latitude', 89]
      index ? max = 59 : null

      let value = parseInt(this[name][index], 10)
      if (isNaN(value)) {
        value = 0;
      }
      value = value < 0 ? 0 : value
      value = value > max ? max : value
      this.$set(this[name], index, value)
      this.returnBackFn()
    },

    /**
     * v-model 绑定事件  双向绑定实现
     */
    returnBackFn () {
      let longitude = parseFloat(this.longFlag + this.Dms2D(this.longitude));
      let latitude = parseFloat(this.latFlag + this.Dms2D(this.latitude));
      let array = [longitude, latitude]
      this.$emit('input', array);
    },

    /**
    * 度转度分秒
    */
    D2Dms (d_data = 0) {
      var degree = parseInt(d_data);
      var min = parseInt((d_data - degree) * 60);
      var sec = parseInt((d_data - degree) * 3600 - min * 60);
      return [degree, min, sec];
    },

    /**
    * 度分秒转度
    */
    Dms2D (dms_data = [0, 0, 0]) {
      let d = parseFloat(dms_data[0]);
      let m = parseFloat(dms_data[1]);
      let s = parseFloat(dms_data[2]);
      return this.keepFourDecimal(d + m / 60 + s / 60 / 60);
    },

    /**
    * 保留四位小数,小于四位精度可能丢失
    */
    keepFourDecimal (num) {
      var result = parseFloat(num);
      if (isNaN(result)) {
        return 0;
      }
      result = Math.round(num * 10000) / 10000;
      return result;
    }
  },
}
</script>


<style lang="less" scoped>
@color-border: #9e9e9e;
@height: 28px;
.coordinates {
  border: 1px solid @color-border;
  width: fit-content;
  display: inline-flex;
}

.item:nth-of-type(1) {
  border-right: 1px solid @color-border;
}
.el-input {
  width: 40px;
}

.itude {
  height: @height;
  line-height: @height;
  display: inline-block;
  padding-left: 5px;
  cursor: pointer;
  user-select: none;
}

i {
  font-size: 18px;
  color: gray;
}
</style>

<style lang="less">
.el-input__inner {
  text-align: center;
  border: none;
  border-radius: unset;
}

.el-input--suffix .el-input__inner {
  padding: 0;
}
</style>

复制代码

测试代码 index.vue

<template>
  <div id="example">
    <Coordinates ref="coordinates"
                 v-model="value"></Coordinates>
    <el-button @click="changeValue"
               type="primary">
      change value
    </el-button>
    <br>
    <span>value:{{value.toString()}}</span>
    <br>
    <span>度分秒格式:{{formatString.toString()}}</span>
    <el-button @click="refresh"
               type="primary">
      refresh
    </el-button>
  </div>
</template>
<script>

import Coordinates from '@/components/Coordinates'
export default {
  name: 'index',
  components: {
    Coordinates
  },
  data () {
    return {
      value: [12.34, -45.67],
      formatString: []
    }
  },
  mounted () {
    this.refresh ()
  },
  methods: {
    changeValue () {
      this.$set(this.value, 0, (this.value[0] + 2) >= 180 ? 0 : (this.value[0] + 2))
      this.$set(this.value, 1, (this.value[1] + 2) >= 90 ? 0 : (this.value[1] + 2))
      setTimeout(() => {
        refresh ()
      }, 10);

    },
    refresh () {
      // 获取度分秒格式
      this.formatString = this.$refs.coordinates.formatString
    }
  }
}
</script>

<style lang="less" scoped>
#example {
  padding: 20px;
}

.el-button {
  margin: 20px;
}

span {
  font-size: 17px;
}
</style>

复制代码

效果

修改子组件值 父组件的value会改变,修改父组件的value,子组件会自动修改, [change value] 按钮 可以修改value [refresh] 按钮 通过ref获取度分秒格式的经纬度

基于elementUI的一个使用v-model实现的经纬度输入的vue组件
基于elementUI的一个使用v-model实现的经纬度输入的vue组件

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Linux Command Line

The Linux Command Line

William E. Shotts Jr. / No Starch Press, Incorporated / 2012-1-17 / USD 39.95

You've experienced the shiny, point-and-click surface of your Linux computer-now dive below and explore its depths with the power of the command line. The Linux Command Line takes you from your very ......一起来看看 《The Linux Command Line》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器