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


Posted in Javascript onMay 12, 2019
  • 绑定一个 [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>

实现

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 []
 }
}

model: prop为 value 时不用实现 model 但是this.$emit(event,arg) 传入的event需要为 'input',这里要注意

model: { 
 prop: 'value',
 event: 'input'
},

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组件

总结

以上所述是小编给大家介绍的基于elementUI使用v-model实现经纬度输入的vue组件,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

Javascript 相关文章推荐
一个可以兼容IE FF的加为首页与加入收藏实现代码
Nov 02 Javascript
jquery使用$(element).is()来判断获取的tagName
Aug 24 Javascript
jQuery的Each比JS原生for循环性能慢很多的原因
Jul 05 Javascript
微信小程序 向左滑动删除功能的实现
Mar 10 Javascript
Angular.Js之Scope作用域的学习教程
Apr 27 Javascript
Vue的轮播图组件实现方法
Mar 03 Javascript
jQuery 实现批量提交表格多行数据的方法
Aug 09 jQuery
JS实现深度优先搜索求解两点间最短路径
Jan 17 Javascript
JQuery获取元素尺寸、位置及页面滚动事件应用示例
May 14 jQuery
JavaScript创建表格的方法
Apr 13 Javascript
vue实现图片按比例缩放问题操作
Aug 11 Javascript
vue 使用 v-model 双向绑定父子组件的值遇见的问题及解决方案
Mar 01 Vue.js
vue组件中watch props根据v-if动态判断并挂载DOM的问题
May 12 #Javascript
用js简单提供增删改查接口
May 12 #Javascript
electron-vue利用webpack打包实现多页面的入口文件问题
May 12 #Javascript
vue中axios实现数据交互与跨域问题
May 12 #Javascript
jquery3和layui冲突导致使用layui.layer.full弹出全屏iframe窗口时高度152px问题
May 12 #jQuery
JS块级作用域和私有变量实例分析
May 11 #Javascript
微信小程序封装的HTTP请求示例【附升级版】
May 11 #Javascript
You might like
探讨:使用XMLSerialize 序列化与反序列化
2013/06/08 PHP
PHP采用XML-RPC构造Web Service实例教程
2014/07/16 PHP
一键生成各种尺寸Icon的php脚本(实例)
2017/02/08 PHP
PHP Laravel 上传图片、文件等类封装
2017/08/16 PHP
一些有关检查数据的JS代码
2006/09/07 Javascript
查看源码的工具 学习jQuery源码不错的工具
2011/12/26 Javascript
5个最佳的Javascript日期处理类库分享
2012/04/15 Javascript
JS实现从表格中动态删除指定行的方法
2015/03/31 Javascript
深入分析Javascript跨域问题
2015/04/17 Javascript
jquery插件unobtrusive实现片段式加载
2015/06/15 Javascript
Flow之一个新的Javascript静态类型检查器
2015/12/21 Javascript
JS实现的表格操作类详解(添加,删除,排序,上移,下移)
2015/12/22 Javascript
jQuery简单自定义图片轮播插件及用法示例
2016/11/21 Javascript
jQuery实现图片滑动效果
2017/03/08 Javascript
jQuery设置图片等比例缩小的方法
2017/04/29 jQuery
extjs简介_动力节点Java学院整理
2017/07/17 Javascript
arcgis for js栅格图层叠加(Raster Layer)问题
2017/11/22 Javascript
vue使用rem实现 移动端屏幕适配
2018/09/26 Javascript
[01:39:42]Fnatic vs Mineski 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
python列表操作之extend和append的区别实例分析
2015/07/28 Python
详解Python的Twisted框架中reactor事件管理器的用法
2016/05/25 Python
Appium+python自动化之连接模拟器并启动淘宝APP(超详解)
2019/06/17 Python
如何基于python对接钉钉并获取access_token
2020/04/21 Python
英国在线自行车商店:Evans Cycles
2016/09/26 全球购物
C# Debug和Testing相关面试题
2015/10/25 面试题
高中生自我评价个人范文
2013/11/09 职场文书
办公室岗位职责
2014/02/12 职场文书
犯错检讨书
2014/02/21 职场文书
最新大学生创业计划书写作攻略
2014/04/02 职场文书
食品科学与工程专业毕业生求职信范文
2014/07/21 职场文书
2015年幼儿园学前班工作总结
2015/05/18 职场文书
Mac环境Nginx配置和访问本地静态资源的实现
2021/03/31 Servers
python 统计代码耗时的几种方法分享
2021/04/02 Python
Mysql systemctl start mysqld报错的问题解决
2021/06/03 MySQL
Python实现socket库网络通信套接字
2021/06/04 Python
【海涛dota解说】海涛小满开黑4v5被破两路翻盘潮汐第一视角解说
2022/04/01 DOTA