视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
基于elementUI使用v-model实现经纬度输入的vue组件
2020-11-27 21:57:11 责编:小采
文档

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

    下载本文
    显示全文
    专题