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

  • 绑定一个 [12.34,-45.67] (东经西经,南纬北纬 正负表示) 形式的经纬度数组,能够按度分秒进行编辑,效果如下所示,点击东经,北纬可切换。
  • 经纬度的 度转度分秒
  • 能够获取度分秒格式数据

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组件,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

(0)

相关推荐

  • 利用vue+elementUI实现部分引入组件的方法详解

    前言 vue.js的UI组件库,在git上有多个项目,我见的使用者比较多的是iView和Element.两个组件库,组件都很丰富. 官网的介绍 iView: 一套基于 Vue.js 的高质量 UI 组件库 Element,一套为开发者.设计师和产品经理准备的基于 Vue 2.0 的组件库,提供了配套设计资源,帮助你的网站快速成型. 两者各有优缺点,不多评论,根据自己的需求,我最后使用了Element.因为最近公司开发一个很小的后台项目,所以考虑部分引入element的组件,因为第一次单独引入没有

  • vue项目创建并引入饿了么elementUI组件的步骤

    1:安装node 前端开发框架和环境都是需要 Node.js ,先安装node.js开发环境,vue的运行是要依赖于node的npm的管理工具来实现,下载,安装完成之后,打开cmd开始输入命令.(我用的是win10系统,所以需要管理员权限,右键点击以管理员身份运行cmd),不然会出现很多报错. 2:查看node的版本号 输入命令:node -v; 3:安装淘宝npm镜像 由于npm是国外的,使用起来比较慢,我们这里使用淘宝的cnpm镜像来安装vue. 淘宝的cnpm命令管理工具可以代替默认的np

  • vue 自定义组件 v-model双向绑定、 父子组件同步通信的多种写法

    上篇文章给大家介绍了浅析Vue自定义组件的v-model,大家可以参考下.接下来通过本文给大家介绍vue 自定义组件 v-model双向绑定. 父子组件同步通信的多种写法,具体详情如下所示: 父子组件通信,都是单项的,很多时候需要双向通信.方法如下: 1.父组件使用:msg.sync="aa"  子组件使用$emit('update:msg', 'msg改变后的值xxx') 2.父组件传值直接传对象,子组件收到对象后可随意改变对象的属性,但不能改变对象本身. 3.父组件使用: v-mo

  • 利用Vue v-model实现一个自定义的表单组件

    功能描述: 通过点击按钮,可以增减购物数量 组件名称是 CouterBtn 最终效果如下 我们使用 vue-cli搭建基本的开发环境,这也是最快的进行 .vue组件开发的方式 对于入口组件  App.vue (可以暂时忽略其他细节,我们的重点是如何写组件) App.vue <template> <div id="app"> <h4>这是一个利用 v-model实现的自定义的表单组件</h4> <h6>CouterBtn组件的值

  • Vue2.0利用 v-model 实现组件props双向绑定的优美解决方案

    在项目中开始使用vue2来构建项目了,跟 vue1 很大的一处不同在于2 取消了props 的双向绑定,改成只能从父级传到子级的单向数据流,初衷当然是好的,为了避免双向绑定在项目中容易造成的数据混乱. 解决方案一 然后开始参考网上和github上的方案等等,发现很多解决方案是这样的 用data对象中创建一个props属性的副本 watch props属性 赋予data副本 来同步组件外对props的修改 watch data副本,emit一个函数 通知到组件外 这里以最常见的 modal为例子:

  • vue项目中v-model父子组件通信的实现详解

    前言 我们在vue项目中,经常有这样的需求,父组件绑定v-model,子组件输入更改父组件v-model绑定的数值.很多朋友对这种操作不是很清楚,这需要对v-model有比较深入的了解,今天谈谈v-model. vue的双向数据绑定 v-model这个指令只能用在<input>, <select>,<textarea>这些表单元素上,所谓双向绑定,指的就是我们在js中的vue实例中的data与其渲染的dom元素上的内容保持一致,两者无论谁被改变,另一方也会相应的更新为相

  • 详解如何在vue项目中引入elementUI组件

    前提:已经安装好Vue 初始化vue vue init webpack itemname 运行初始化demo 运行一下初始后的demo,如果没有问题则进行安装elementUI npm run dev 安装 elementUI npm i element-ui -S 引入elementUI 在main.js中引入elementUI import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vu

  • Vue项目引进ElementUI组件的方法

    环境要求 Nodejs Nodejs 官网下载地址:http://nodejs.cn/download/具体安装参考其他资料 打开cmd命令行,输入npm -v,如果出现如下图的显示,说明已经安装正确. 如果安装版本比较老,想升级新版本 npm install npm -g 安装 webpack 安装webpack npm install webpack -g -g 表示安装为全局 安装 vue-cli 安装 vue 脚手架项目初始化工具 vue-cli npm install vue-cli

  • 浅析Vue自定义组件的v-model

    最近在学习vue,今天看到自定义事件的表单输入组件,纠结了一会会然后恍然大悟...官方教程写得不是很详细,所以我决定总结一下. v-model语法糖 v-model实现了表单输入的双向绑定,我们一般是这么写的: <div id="app"> <input v-model="price"> </div> new Vue({ el: '#app', data: { price: '' } }); 通过该语句实现price变量与输入值双

  • vue如何在自定义组件中使用v-model

    v-model指令 所谓的"指令"其实就是扩展了HTML标签功能(属性). 先来一个组件,不用vue-model,正常父子通信 <!-- parent --> <template> <div class="parent"> <p>我是父亲, 对儿子说: {{sthGiveChild}}</p> <Child @returnBack="turnBack" :give="st

  • vue 2.0组件与v-model详解

    前言 大家可能乍一看这个标题,可能会有疑问:v-model和组件也能扯到一起?在打算写这篇文章的时候,也是这么想的.咱们按简历的那一套STAR法则来梳理一下这篇文章: 情景[Situation]: 编写通用的输入组件时,子组件要绑定到父组件的某个变量上dataA,当父组件要拿到自组件的值时不能通过this.$children.xxx取值然后付给dataA, 而是父组件可以直接this.dataA就可以取到当前子组件最新值. 任务[Task]: 实现在父组件直接this.dataA就可以取到当前子

随机推荐