✨✨使用vue3打造一个el-form表单及高德地图的关联组件实例✨

✨1. 实现功能

  1. 🌟表单内显示省市县以及详细地址
    • 点击省市县输入框时,打开对应地图弹窗,进行位置选择
    • 选择位置回显入对应输入框
    • 表单内的省市县以及地址输入框同外嵌表单走相同的校验方式
    • 触发校验后点击reset实现清除校验与清空数据
  2. 🌟地图内展示地址搜索框以及地图坐标图
    • 搜索框展示当前经纬度地址
    • 搜索框可输入自定义地址,下拉菜单展示范围兴趣点和道路信息,点击可进行搜索
  3. 🌟 单独封装每个组件,使form-itemdialog以及amap三个组件可单独使用

✨2. 示例图

  1. 💖示例图1:💖
    在这里插入图片描述

  2. 💖💖示例图2:💖
    在这里插入图片描述

  3. 💖💖💖示例图3:💖
    在这里插入图片描述

  4. 💖💖💖💖示例图4:💖
    在这里插入图片描述

  5. 💖💖💖💖💖示例图5:💖
    在这里插入图片描述

✨3. 组件代码

🌹1. 组件目录结构

在这里插入图片描述

2. 🍗 🍖地图组件AmapContainer.vue
<template><div v-loading="loading"><input type="text" class="address" v-model="iMap.address" id="inputAddress" /><div id="container"></div></div>
</template><script setup lang="ts" name="AmapContainer">
import { ref, reactive, computed, watch, onMounted, onUnmounted } from "vue";
import AMapLoader from "@amap/amap-jsapi-loader";
import { AMAP_MAP_KEY, AMAP_SECRET_KEY } from "@/config";
import { getBrowserLang } from "@/utils";
import { useGlobalStore } from "@/stores/modules/global";
import { IMap } from "../interface/index";const globalStore = useGlobalStore();
const language = computed(() => {if (globalStore.language == "zh") return "zh_cn";if (globalStore.language == "en") return "en";return getBrowserLang() == "zh" ? "zh_cn" : "en";
});const loading = ref(true);interface ExtendsWindow extends Window {_AMapSecurityConfig?: {securityJsCode: string;};
}
let _window: ExtendsWindow = window;// 定义map实例
let map: any = null;const iMap = reactive<IMap>({province: "",city: "",district: "",address: "",lnglat: [114.525918, 38.032612],canSubmit: true
});watch(() => iMap.address,() => {iMap.canSubmit = !iMap.address;}
);onMounted(() => {initMap();
});onUnmounted(() => {map?.destroy();
});// 初始化地图
const initMap = async () => {_window._AMapSecurityConfig = {securityJsCode: AMAP_SECRET_KEY // ❓高德秘钥👇👇下方会有👇👇};AMapLoader.load({key: AMAP_MAP_KEY, // ❓申请好的Web端开发者Key,首次调用 load 时必填👇👇下方会有👇👇version: "2.0", // ❓指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15plugins: ["AMap.ToolBar", "AMap.Scale", "AMap.Marker", "AMap.Geocoder", "AMap.AutoComplete"] //需要使用的的插件列表}).then(AMap => {map = new AMap.Map("container", {// 设置地图容器idviewMode: "2D", // 是否为3D地图模式zoom: 11, // 初始化地图级别center: iMap.lnglat // 初始化地图中心点位置});//创建工具条插件实例const toolbar = new AMap.ToolBar({position: {top: "110px",right: "40px"}});map.addControl(toolbar);//创建比例尺插件实例const Scale = new AMap.Scale();map.addControl(Scale);//创建标记插件实例const Marker = new AMap.Marker({position: iMap.lnglat});map.addControl(Marker);//创建地理编码插件实例const Geocoder: any = new AMap.Geocoder({radius: 1000, //以已知坐标为中心点,radius为半径,返回范围内兴趣点和道路信息extensions: "base", //返回地址描述以及附近兴趣点和道路信息,默认“base | all”lang: language.value});//返回地理编码结果Geocoder.getAddress(iMap.lnglat, (status, result) => {if (status === "complete" && result.info === "OK") {iMap.province = result.regeocode.addressComponent.province;iMap.city = result.regeocode.addressComponent.city;iMap.district = result.regeocode.addressComponent.district;iMap.address = result.regeocode.formattedAddress;AutoComplete.setCity(iMap.address);loading.value = false;}});// 根据输入关键字提示匹配信息const AutoComplete = new AMap.AutoComplete({input: "inputAddress",city: iMap.address,datatype: "all",lang: language.value});AutoComplete.on("select", result => {iMap.lnglat = [result.poi.location.lng, result.poi.location.lat];setPointOrAddress();});//点击地图事件map.on("click", e => {iMap.lnglat = [e.lnglat.lng, e.lnglat.lat];setPointOrAddress();});// 设置地图点坐标与位置交互const setPointOrAddress = () => {Marker.setPosition(iMap.lnglat);map.setCenter(iMap.lnglat);map.setZoom(12);Geocoder.getAddress(iMap.lnglat, (status, result) => {if (status === "complete" && result.info === "OK") {iMap.province = result.regeocode.addressComponent.province;iMap.city = result.regeocode.addressComponent.city;iMap.district = result.regeocode.addressComponent.district;iMap.address = result.regeocode.formattedAddress;}});};}).catch(e => {console.log(e);});
};defineExpose({iMap
});
</script><style scoped lang="scss">
@import "../index.scss";
</style><style lang="scss">
.amap-sug-result {z-index: 10000;
}
</style>
🍀3. 弹窗组件AmapDialog.vue 🍀
<template><el-dialog :model-value="visible" title="请选择" width="800" :before-close="handleClose"><AmapContainer ref="amapContainer" /><template #footer><div class="dialog-footer"><el-button @click="handleClose">取消</el-button><el-button type="primary" :disabled="amapContainer?.iMap?.canSubmit" @click="handleConfirm">确认</el-button></div></template></el-dialog>
</template><script setup lang="ts" name="AmapExplore">
/*🔻// 使用方式// ❤️amapFlag: 控制弹窗显隐// ❤️iMap必须ref定义, 接收选择地址数据// 示例:// 💥<AmapExplore v-model:visible="amapFlag" v-model:amap="iMap" />💥
*/ 🔺 
import { ref, withDefaults } from "vue";
import { IAddress } from "../interface/index";
import AmapContainer from "./AmapContainer.vue";withDefaults(defineProps<{visible: boolean;amap: Partial<IAddress>;}>(),{visible: false}
);const amapContainer = ref();// 定义emits
const emits = defineEmits<{"update:amap": [value: IAddress];"update:visible": [value: boolean];
}>();const handleConfirm = () => {// delete amapContainer.value?.iMap?.canSubmit;emits("update:amap", amapContainer.value?.iMap);handleClose();
};const handleClose = () => {emits("update:visible", false);
};
</script><style scoped lang="scss"></style>
🌼4. 表单组件AmapExplore/index.vue 🌼
<template><el-row :gutter="gutter" :style="gutterStyle"><el-col :span="8"><el-form-item prop="province"><el-inputv-model="iMapForm.province"ref="provinceRef"placeholder="省"size="large"style="width: 100%"@click="handleAmapChange"></el-input></el-form-item></el-col><el-col :span="8"><el-form-item prop="city"><el-inputv-model="iMapForm.city"ref="cityRef"placeholder="市"size="large"style="width: 100%"@click="handleAmapChange"></el-input></el-form-item></el-col><el-col :span="8"><el-form-item prop="district"><el-inputv-model="iMapForm.district"ref="districtRef"placeholder="县"size="large"style="width: 100%"@click="handleAmapChange"></el-input></el-form-item></el-col></el-row><el-col :span="24"><el-form-item prop="address"><el-input v-model="iMapForm.address" placeholder="请输入详细地址" size="large" style="width: 100%"></el-input></el-form-item></el-col><AmapDialog v-model:visible="amapFlag" v-model:amap="iMapForm" />
</template><script setup lang="ts" name="AmapExplore">
import { ref, reactive, watch, inject, watchEffect } from "vue";
import type { FormRules } from "element-plus";
import { IAddress } from "./interface/index";
import AmapDialog from "./components/AmapDialog.vue";// 栅格间隔与样式
const gutter = 20;
const gutterStyle = {width: `calc(100% + ${gutter}px)`,"margin-bottom": `${gutter}px`
};// 接收传入的formData和formRules
const { ruleForm, rules } = inject<{ ruleForm: Object; rules: any }>("aMap", { ruleForm: reactive({}), rules: reactive({}) });const iMapForm = ref<IAddress>({province: "",city: "",district: "",address: "",lnglat: []
});// 若地址有值,则赋予formData
watch(() => iMapForm,n => {// 为防止重复赋值if (n.value.province || n.value.city || n.value.district || n.value.address) {Object.assign(ruleForm, { ...iMapForm.value });}},{deep: true}
);// 另处理经纬度lnglat
watch([() => iMapForm.value.province, () => iMapForm.value.city, () => iMapForm.value.district], n => {if (n.some(item => !item)) {iMapForm.value.lnglat = [];}
});watch(() => iMapForm.value.lnglat,n => {if (!n.length) {Object.assign(ruleForm, iMapForm.value);}}
);// 将formData赋值给iMapForm-主要作用为清空重置
watchEffect(() => {Object.assign(iMapForm.value, { ...ruleForm });
});// form校验;
const iMapRules = reactive<FormRules<IAddress>>({province: [{ required: true, message: "请选择省", trigger: ["blur", "change"] }],city: [{ required: true, message: "请选择市", trigger: ["blur", "change"] }],district: [{ required: true, message: "请选择区、县", trigger: ["blur", "change"] }],address: [{ required: true, message: "请输入详细地址", trigger: ["blur", "change"] }]
});// 合并校验数据;
watch(rules, () => Object.assign(rules, { ...iMapRules }), {immediate: true,deep: true
});// 地图弹窗
const amapFlag = ref<boolean>(false);
const provinceRef = ref();
const cityRef = ref();
const districtRef = ref();
const handleAmapChange = () => {amapFlag.value = true;provinceRef.value.blur();cityRef.value.blur();districtRef.value.blur();
};
</script><style scoped lang="scss"></style>
5. 🌿scss文件 🌿
// AmapContainer
.address {box-sizing: border-box;width: 100%;height: 30px;padding: 0 12px;margin-bottom: 10px;line-height: 30px;border: 1px solid #ececec;border-radius: 4px;
}
#container {width: 100%;height: 400px;padding: 0;margin: 0;
}
🌴6. 类型定义interface/index.ts 🌴
export interface IAddress {province: string;city: string;district: string;address: string;lnglat: number[];
}
export interface IMap extends IAddress {canSubmit: boolean;
}
❕ ❕7. 地图组件内使用的高德AMAP_MAP_KEY和秘钥AMAP_SECRET_KEY可以自行设置

// 高德地图 key
export const AMAP_MAP_KEY: string = "****";
// 高德地图 安全密钥
export const AMAP_SECRET_KEY: string = "*****";

✨4. 父组件使用😎

  1. ☝️ 使用组件

<!-- 1. 使用组件 -->
<AmapExplore />
  1. ✌️使用provide向后代传入表单数据formData)和校验规则formRules

// 2. 传入formData和formRules
provide("aMap", { ruleForm, rules });
  1. 👋完整代码示例:
<template><div class="card amap-example"><el-form ref="ruleFormRef" :model="ruleForm" :rules label-width="auto" style="max-width: 600px"><el-form-item label="Activity name" prop="name"><el-input v-model="ruleForm.name" /></el-form-item><el-form-item label="地址" required><!-- 1. 使用组件 --><AmapExplore /></el-form-item><el-form-item label="备注" prop="remark"><el-input v-model="ruleForm.remark" /></el-form-item><el-form-item><el-button type="primary" @click="submitForm(ruleFormRef)"> Create </el-button><el-button @click="resetForm(ruleFormRef)">Reset</el-button></el-form-item></el-form></div>
</template><script setup lang="ts" name="amapExample">
import { reactive, ref, provide } from "vue";
import type { FormInstance, FormRules } from "element-plus";
import AmapExplore from "@/components/AmapExplore/index.vue";interface RuleForm {name: string;remark: string;
}
const ruleFormRef = ref<FormInstance>();
let ruleForm = reactive<RuleForm>({name: "",remark: ""
});let rules = reactive<FormRules<RuleForm>>({name: [{ required: true, message: "请输入姓名", trigger: "blur" }],remark: [{ required: true, message: "请输入备注", trigger: "blur" }]
});// 2. 传入formData和formRules
provide("aMap", { ruleForm, rules });const submitForm = async (formEl: FormInstance | undefined) => {console.log(ruleForm, "s");if (!formEl) return;await formEl.validate((valid, fields) => {if (valid) {console.log("submit!");} else {console.log("error submit!", fields);}});
};const resetForm = (formEl: FormInstance | undefined) => {if (!formEl) return;formEl.resetFields();
};
</script>

❗️ 5. 封装实例缺点💦

  1. 当选择地址之后,再次打开地图弹窗,更改地图标记点,地址会实时变更,
  2. 不论点击取消还是确认按钮,都会改变表单内部值
  3. 💢初始不会出现此问题💢
  4. 💪后续会改进😁😁😁😁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/325568.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习中的注意力机制一(Pytorch 15)

一 简介 灵长类动物的视觉系统接受了大量的感官输入&#xff0c;这些感官输入远远超过了大脑能够完全处理的程度。然而&#xff0c; 并非所有刺激的影响都是相等的。意识的聚集和专注使灵长类动物能够在复杂的视觉环境中将注意力引向感 兴趣的物体&#xff0c;例如猎物和天敌。…

sqli-labs 第八关盲注python脚本

目录 ​编辑 判断库名 1.库名长度 2.库名 import requests import mathurl "http://127.0.0.1/Less-8"def dblength():for i in range(20):payload f"1 and length(database())>{i}-- "data {id: payload}res requests.get(url, paramsdata)if …

Google与哈佛大学的科学家团队共同创造了一张人脑中一个极小部分的精细地图

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

华为交换机基础配置命令

01常用命令视图 02创建VLAN //用户视图&#xff0c;一般display命令查看信息比较多。 system-view //准备进入系统视图。 [Huawei]vlan 100 //创建vlan 100。 [Huawei-vlan100]quit //退回系统视图。 03将端口加入到vlan中 [Huawei] interface GigabitEthernet2/0/1 //(10G光口…

Python爬虫实战:爬取【某旅游交通出行类网站中国内热门景点】的评论数据,使用Re、BeautifulSoup与Xpath三种方式解析数据,代码完整

一、分析爬取网页&#xff1a; 1、网址 https://travel.qunar.com/2、 打开网站&#xff0c;找到要爬取的网页 https://travel.qunar.com/p-cs299979-chongqing进来之后&#xff0c;找到评论界面&#xff0c;如下所示&#xff1a;在这里我选择驴友点评数据爬取点击【驴友点评…

Ardupilot开源代码之Rover上路 - 后续1

Ardupilot开源代码之Rover上路 - 后续1 1. 源由2. 问题汇总2.1 问题1&#xff1a;飞控选择2.2 问题2&#xff1a;飞控安装位置和固定2.3 问题3&#xff1a;各种插头、插座配套2.4 问题4&#xff1a;分电板缺陷2.5 问题5&#xff1a;电机编码器接线及正反向问题2.6 问题6&#x…

springboot+vue+mybatis灵活就业服务平台+PPT+论文+讲解+售后

随着网络科技的不断发展以及人们经济水平的逐步提高&#xff0c;网络技术如今已成为人们生活中不可缺少的一部分&#xff0c;而微信小程序是通过计算机技术&#xff0c;针对用户需求开发与设计&#xff0c;该技术尤其在各行业领域发挥了巨大的作用&#xff0c;有效地促进了灵活…

YOLOv9全网最新改进系列:YOLOv9完美融合标准化的注意力模块NAM,高效且轻量级的归一化注意力机制,助力目标检测再上新台阶!

YOLOv9全网最新改进系列&#xff1a;YOLOv9完美融合标准化的注意力模块NAM&#xff0c;高效且轻量级的归一化注意力机制&#xff0c;助力目标检测再上新台阶&#xff01;&#xff01;&#xff01; YOLOv9原文链接戳这里&#xff0c;原文全文翻译请关注B站Ai学术叫叫首er B站全…

win11个性化锁屏界面怎么关闭?

win11个性化锁屏界面关闭方法对于win11用户来说&#xff0c;关闭个性化锁屏界面是一个常见问题。本文将由php小编苹果详细介绍如何执行此操作&#xff0c;分步指导并提供操作截图。继续阅读以了解具体步骤。 win11个性化锁屏界面关闭方法 第一步&#xff0c;点击底部Windows图…

「 安全设计 」68家国内外科技巨头和安全巨头参与了CISA发起的安全设计承诺,包含MFA、默认密码、CVE、VDP等七大承诺目标

美国网络安全和基础设施安全局&#xff08;CISA&#xff0c;CyberSecurity & Infrastructure Security Agency&#xff09;于2024年5月开始呼吁企业是时候将网络安全融入到技术产品的设计和制造中了&#xff0c;并发起了安全设计承诺行动&#xff0c;该承诺旨在补充和建立现…

唤醒手腕 Go 语言 并发编程、Channel通道、Context 详细教程(更新中)

并发编程概述 ​ 一个进程可以包含多个线程&#xff0c;这些线程运行的一定是同一个程序&#xff08;进程程序&#xff09;&#xff0c;且都由当前进程中已经存在的线程通过系统调用的方式创建出来。进程是资源分配的基本单位&#xff0c;线程是调度运行的基本单位&#xff0c…

贪吃蛇——C语言实践

目录 1. 游戏效果演示 2. 课程目标 3.项目适合对象 4.技术要点 5. Win32 API介绍 5.1 Win32 API 5.2 控制台程序 5.3 控制台屏幕上的坐标COORD 5.4 GetStdHandle 5.5 GetConsoleCursorInfo 5.5.1 CONSOLE_CURSOR_INFO 5.6 SetConsoleCursorInfo 5.7 SetConsoleCurs…

uniapp开发小程序使用vue的v-html解析富文本图片过大过宽显示超过屏幕解决办法

如果没有设置的话&#xff0c;就会导致图片溢出&#xff0c;过宽显示或者错位显示&#xff0c;显示效果非常的丑陋&#xff1a; 修改后显示的效果&#xff1a; 网上比较low的解决办法&#xff1a;网上各种解决方法核心思想就是在数据层把数据模板上的img数据加上style样式&…

在vue3中,如何优雅的使用echarts之实现大屏项目

前置知识 效果图 使用技术 Vue3 Echarts Gasp Gasp&#xff1a;是一个 JavaScript动画库,它支持快速开发高性能的 Web 动画。在本项目中&#xff0c;主要是用于做轨迹运动 所需安装的插件 npm i echarts npm i countup.js 数字滚动特效 npm i gsap javascript动画库 np…

蓝桥杯-网络安全比赛(6) 模拟实验 Metasploit 控制并获取Windows 登录HASH、LM Hash和NTLM Hash密文解析

窃取WINDOWS账号密码 系统环境&#xff1a;主机&#xff08;Windows系统 IP&#xff1a;192.168.126.129)&#xff0c;虚拟机&#xff08;KALI系统 IP&#xff1a;192.168.126.3&#xff09;&#xff0c;两者需要能通过本地网络互通互连。 攻击工具&#xff1a;Metasploit是一…

基于EBAZ4205矿板的图像处理:12图像二值化(阈值可调)

基于EBAZ4205矿板的图像处理&#xff1a;12图像二值化(阈值可调) 我的项目是基于EBAZ4205矿板的阈值可调的图像阈值二值化处理&#xff0c;可以通过按键调整二值化的阈值&#xff0c;key1为阈值加1&#xff0c;key4为阈值减1&#xff0c;key2为阈值加10&#xff0c;key5为阈值…

java项目之校园失物招领系统(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的校园失物招领系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 校园失物招领系统的主要…

如何更好地使用Kafka? - 运行监控篇

要确保Kafka在使用过程中的稳定性&#xff0c;需要从kafka在业务中的使用周期进行依次保障。主要可以分为&#xff1a;事先预防&#xff08;通过规范的使用、开发&#xff0c;预防问题产生&#xff09;、运行时监控&#xff08;保障集群稳定&#xff0c;出问题能及时发现&#…

LLaMA 羊驼系大语言模型的前世今生

关于 LLaMA LLaMA是由Meta AI发布的大语言系列模型&#xff0c;完整的名字是Large Language Model Meta AI&#xff0c;直译&#xff1a;大语言模型元AI。Llama这个单词本身是指美洲大羊驼&#xff0c;所以社区也将这个系列的模型昵称为羊驼系模型。 Llama、Llama2 和 Llama3…

前端笔记-day02

文章目录 01-无序列表02-有序列表03-定义列表04-表格06-表格-合并单元格07-表单-input08-表单-input占位文本09-表单-单选框10-表单-上传多个文件11-表单-多选框12-表单-下拉菜单13-表单-文本域14-表单-label标签15-表单-按钮16-无语义-span和div17-字体实体19-注册登录页面 01…