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

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

内容简介:一个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 Shallows

The Shallows

Nicholas Carr / W. W. Norton & Company / 2010-6-15 / USD 26.95

"Is Google making us stupid?" When Nicholas Carr posed that question, in a celebrated Atlantic Monthly cover story, he tapped into a well of anxiety about how the Internet is changing us. He also crys......一起来看看 《The Shallows》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具