likes
comments
collection
share

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

作者站长头像
站长
· 阅读数 15

技术背景

Vue3是目前最新版本的Vue.js框架,它引入了很多新的特性和改进,包括更好的性能、更灵活的组合式APITypescript的原生支持等。Pinia是一款基于Vue3的状态管理库,它提供了类似于Vuex的功能,同时还充分利用了Vue3的响应式系统和Composition API,使得状态管理更加简单和高效。

VueRouterVue.js官方的路由管理器,它能够帮助我们实现SPA(单页应用)的页面切换和导航功能。而高德地图API是一组提供地图展示、位置定位、路径规划等功能的前端API,它可以与Vue框架无缝集成,用于展示地图和处理地理位置相关的业务逻辑。

项目构建

首先,在存放项目文件的文件内,通过cmd打开管理员窗口。使用vue系列创建项目的方式也就是脚手架,或者通过vue3配套的vite创建项目的方式。(本文以vue3+yarn项目方式为例)

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

等待下载完即可,再者为项目取名。

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

还是和老样子,项目取名之后就是技术栈的选项了。

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

这里我用的JavaScript,相对于的typescript来说它更严谨,一般在大公司或者大型的项目中会用到。

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

到这一步项目已算是创建好了,cd到项目里面,再通过yarn下载依赖

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

yarn下完之后,因为要向后端请求数据再下载axios用来封装服务器的接口

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

此外也可以再下载css的预处理器,sass来写页面的样式或者可以直接使用原生的CSS

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

再者就下载路由(vueRouter)

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

pinia的安装。之后再yarn dev启动项目即可。

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

然后在项目文件里面的src内创建两个文件夹storeRouter,一个完整的项目就创建好了。

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

配置路由和pinia

Router配置

可在src内,创建views的文件夹,用来管理页面。并创建三个页面。

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

随后在Router里面配置路由,首先,我们使用import语句导入了createRoutercreateWebHashHistory函数以及相关的组件。接下来,我们使用createRouter函数创建了一个路由对象。

history: createWebHashHistory()指定了路由模式为哈希模式,使用URL的哈希值来进行路由导航。

routes:是一个路由配置数组,定义了不同路径和对应的组件。

path:指定了路径,可以是字符串也可以是正则表达式。

name:是路由的名称,可以在路由导航中使用。

component:是对应的组件,可以通过import导图页面从而达到路由的赖加载。

最后,使用export default语句输出了这个路由对象。

// 配置路由
import { createRouter, createWebHashHistory } from 'vue-router'
import App from '../App.vue'
const router = createRouter({
    history: createWebHashHistory(),
    routes: [
        {
            path: '/',
            name: 'App',
            component: App,
        },
        {
            path: '/pagesone',
            name: 'pagesone',
            component: () => import('../views/PagesOne.vue')
        },
        {
            path: '/pagetwo',
            name: 'pagetwo',
            component: () => import('../views/PagesTwo.vue')
        },
        {
            path: '/pagesthree',
            name: 'pagesthree',
            component: () => import('../views/PagesThree.vue')
        }
    ]
})
export default router;
全局配置Router+pinia

main.js里面导入配置好的Router路由,用createApp函数创建一个Vue应用实例,并将根组件App作为参数传入。然后,我们调用app.use(router)方法,将路由对象作为插件使用。这样,Vue应用就可以使用VueRouter提供的路由功能了。

pinia也是一样,从pinia库中导入createPinia函数,pinia是一个状态管理库,类似于Vuex,但更简单和灵活。使用createPinia函数创建一个新的pinia实例。将pinia实例添加到Vue应用中,这样Vue应用就可以使用pinia的功能了。

import { createApp } from 'vue'
import './style.css'
// 引入路由
import router from './router/index'
  // 配置pinia
import { createPinia } from 'pinia'
import App from './App.vue'
let pinia = createPinia()
const app = createApp(App)
app.use(router)
app.use(pinia)
app.mount('#app')
使用路由

App.vue使用VueRouter来创建一个tabs包含三个可切换标签页的界面,每个标签页都有自己的路由和显示内容。就相当于是一个选项卡功能。

<template>
  <div class="home-container">
<!--     其他页面路由入口 -->
      <div class="content">
          <RouterView></RouterView>
      </div>
      <!-- tabs标签切换 -->
      <div class="tabs-pages">
          <div class="tabs" v-for="item in tabs" :key="item">
              <RouterLink class="tabs-router" :to="item.link">{{ item.title }}</RouterLink>
          </div>
      </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { RouterView,RouterLink } from 'vue-router';

let tabs = ref([
  {
      title: 'A',
      link: '/pagesone'
  },
  {
      title: 'B',
      link: '/pagetwo'
  },
  {
      title: 'C',
      link: '/pagesthree'
  }
])

</script>

封装接口

src文件下面,创建两个文件utilsapis,一个用来封装服务器接口,一个用来封装获取数据的接口。

首先是utils

// 封装axios
import axios from 'axios'; //引入axios

export const Url = '后端提供的服务器接口'

const http = axios.create({
    // 服务器地址
    baseURL: Url,
    // 设置超时
    timeout:10000
})
// 请求拦截器
http.interceptors.request.use((reqconfig) => {
    // 在当前请求配置对象上,挂Authorization授权数据
    reqconfig.headers.Authorization = localStorage.token
    // 返回修改的数据
    return reqconfig
})
// 暴露
export default http;

apis获取数据接口封装

<!-- 将服务器接口引入 -->
import http from '../utils/http'
<!-- http.请求方式 -->
export const $_cities = () => http.get('获取数据接口')

获取数据

页面A

在第一个页面,请求数据

<script setup>
// 引入获取城市列表的接口
import { $_cities } from '../apis/cities'
import { ref } from 'vue'
  
// 声明变量接收数据
let cityData = ref({})
// 发送请求获取数据
$_cities().then(res => {
    console.log(res);
})
</script>

获取数据打印出来的效果

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

虽然这样直接拿到了数据,但是一个数组里面包含了611个数据,所以我们需要定义一个响应式引用cityData,在获取到城市列表数据后,首先提取出所有城市的首字母并转换为大写,然后去重并排序。接着,根据首字母创建一个对象,对象的每个属性都是一个数组,用于存储对应首字母的所有城市。最后,将处理后的数据赋值给cityData。使用v-for指令来遍历cityData对象,显示城市列表,并渲染到页面上。

然后给每一个city_name添加一个点击事件,当点击时,会调用clickSon方法并传入当前城市的名字并且页面B里面实时刷新,clickSon方法也可用于改变当前选中的城市并跳转到另一个页面。

完整代码如下:

<template>
    <div>
        <div v-for="(value, groups) in cityData" :key="groups" class="cityList">
            <h2>{{ groups }}</h2>
            <div class="cityName">
                <div :class="{ selected: son == myCityData.citiesData }" @click="clickSon(son)" v-for="son in value"
                    :key="son" class="cityContent">
                    {{ son }}
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>
// 引入获取城市列表的接口
import { $_cities } from '../apis/cities'
import router from '../router';
// 引入pinia
import { useStore } from '../store/cities'
import { ref } from 'vue'

let myCityData = useStore()

let cityData = ref({})

$_cities().then(res => {
    // 获取索取城市的首字母,然后转换为大写
    let initial = res.data.map(city => city.city_pre.toUpperCase())
    // 获取到之后去重
    initial = [...new Set(initial)]
    // 然后使用sort方法对这个数组进行排序
    initial.sort()
    console.log(res);

    // 声明一个对象,用来存储获取到的城市数据
    let cityObj = {}
    for (let groups of initial) {
        cityObj[groups] = []
    }

    // 遍历数组,将获取到的数据push到对应的city中
    for (let city of res.data) {
        let cityPre = city.city_pre.toUpperCase()
        cityObj[cityPre].push(city.city_name)
    }

    // 最后进行赋值
    cityData.value = cityObj
    console.log(cityData.value);
})

// 点击改变城市的名字
let clickSon = city => {
    myCityData.changeCityName(city)
   // 点击城市,跳转到城市对应的map页面
    router.push('/pagetwo')
}
</script>
pinia代码

首先,我们导入了defineStore函数和ref函数。defineStore函数用于定义一个store,而ref函数用于创建一个响应式的数据

然后,我们调用defineStore函数来定义useStore。在定义useStore的回调函数中,我们首先创建了两个响应式的数据:citiesDatacityCode,它们的初始值都为空字符串。

接下来,我们定义了两个函数:changeCityNamechangeCityCodechangeCityName函数用于改变选中城市的名字,它接受一个参数cityName,并将其赋值给citiesDatachangeCityCode函数用于改变城市的代码,它接受一个参数code,并将其赋值给cityCode

最后,我们将citiesDatacityCodechangeCityNamechangeCityCode作为useStore的返回值,使它们可以在其他组件中使用。

// 配置pinia
import { defineStore } from 'pinia'
import { ref } from 'vue'

export const useStore = defineStore('city', () => {
  //城市名字的初始值
  let citiesData = ref('');
  //城市的地理编码
  let cityCode = ref('')
  // 改变选中城市的名字
  let changeCityName =  (cityName) => {
    citiesData.value = cityName
  }
  //改变城市的地理编码               
  let changeCityCode = (code) => {
    cityCode.value = code
  }
  // 返回出去
  return {
    citiesData,
    cityCode,
    changeCityName,
    changeCityCode
  }
})
效果图

此时已实现点击城市,实现页面的跳转和切换城市的功能,接下来在点击城市的同时在B页面刷新该城市的map功能。保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

请求city_name对应的地图

在获取每一个城市所对应的地图之前,需要拿到获取地图的接口(以高德地图为例),直接在高德API里面的开发支持中,选择web服务及web服务API,切换到地理编码点击运行拿到获取地图功能的接口。而获取到对应城市的地图需要三个参数:keyaddresscity。同样的方法切换天气查询即可拿到获取对应城市的天气接口,而获取对应城市的天气的参数就是该城市的地理编码也就是city_code

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

获取key,鼠标滑到个体头像点击应用管理。然后创建新应用,添加key时,这一步只需要选择web服务即可,如此便拿到获取map功能的key值了。

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

封装获取map接口

utils内的map.js使用axios.create方法创建AL_mapaxios实例。在创建实例时,传入一个配置对象,其中包括了baseURLtimeout两个属性。baseURL指定了请求的基础URLmap_iptimeout指定了请求的超时时间为10秒。

最后,我们通过export defaultAL_map实例导出,使其可以在其他模块中使用

// 封装高德地图接口
import axios from 'axios'
const map_ip = 'https://restapi.amap.com'

// 基础封装
const AL_map = axios.create({
    baseURL:map_ip,
    timeout:10000
})
export default AL_map;

然后在apis内的almap.js封装对应的城市map接口和对应城市的天气接口。高德的map接口getpost的请求方式都支持。

// 引入封装好的接口
import AL_map from '../utils/map'

export const web_key = '在创建应用管理拿到的key'
// 获取对应城市地图
export const $_getCityMap = params => AL_map.get('/v3/geocode/geo',{params})
// 获取对应城市的天气
export const $_getCityWeather = params => AL_map.get('/v3/weather/weatherInfo',{params})

页面B获取页面A对应城市的map

获取数据

首先,我们使用import语句导入了useStore函数来获取Piniastore实例,以及$_getCityMap接口和web_key来获取高德地图API的相关函数和密钥。我们还导入了onMountedref函数来处理组件的生命周期和创建响应式数据。

接下来,我们调用useStore函数获取名为cityStorestore实例,并使用storeToRefs函数将store实例中的citiesData转换为响应式数据。然后,我们创建了一个名为cityNameMap的响应式数据,用于存储城市地图数据。

onMounted生命周期钩子中,我们调用$_getCityMap接口来获取城市地图数据。我们传入了web_keycitiesData.value作为参数,其中citiesData.value表示选中的城市数据。

在获取到地图数据后,我们将其赋值给cityNameMap.value

接下来,我们将地图数据保存在Piniastore中,通过调用cityStore.changeCityCode函数来改变城市代码。

最后,我们使用获取到的经纬度创建了一个地图实例,并设置了地图的视图模式、缩放级别和中心点。

完整代码如下:

<template>
    <div>
        
        <div id="container" class="container"></div>
    </div>
</template>

<script setup>
import { useStore } from '../store/cities'
// 封装好获取城市map的接口
import { $_getCityMap, web_key } from '../apis/almap'
import { onMounted, ref } from 'vue';
// 转换响应数据
import { storeToRefs } from 'pinia';

const cityStore = useStore()
const { citiesData } = storeToRefs(cityStore)
const cityNameMap = ref({})
// 获取map的节点所以要用到onMounted
onMounted(() =>{ 
$_getCityMap({
    key: web_key,//获取到的key
    address: citiesData.value, //城市的名字city_name
    city: citiesData.value
}).then(res => {
    cityNameMap.value = res.data.geocodes[0]
    console.log(res);

    // 将数据保存在pinia中
    cityStore.changeCityCode(cityNameMap.value.adcode);

    // 获取经纬度,创建地图
    const map = new AMap.Map('container', {
        viewMode: '2D',  // 默认使用 2D 模式
        zoom: 11,  //初始化地图层级
        center: cityNameMap.value.location.split(',')  //初始化地图中心点
    });
})
})
</script>
// 地图一定要给宽高,否则出不来
<style lang="scss" scoped>
.container {
    width: 100%;
    height: 600px;
}
</style>
实现效果图

当我们随机点击A页面中的某一个城市,并且跳转到页面时。即可实现不同页面跳转实时刷新数据的功能啦。

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

页面C实现A页面对应城市的天气

获取数据

还是一样的操作import语句导入了useStore函数来获取Piniastore实例,以及$_getCityWeather接口和web_key来获取高德地图API的相关函数和密钥。我们还导入了ref函数来创建响应式数据。打印出请求到的数据。

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

然后,我们使用useStore函数获取名为cityWeatherstore实例,并创建了两个响应式数据weatherDataweatherIcon,分别用于存储天气数据和天气图标。

$_getCityWeather函数中,我们传入了web_keycityWeather.cityCode作为参数,其中cityWeather.cityCode表示选中的城市代码。

完整代码如下:

<template>
    <div class="three-container">
        <div class="content">
            <img class="weather-img" :src="weatherIcon">
            <H3>{{ weatherData.province }}-{{ weatherData.city }}-天气:{{ weatherData.weather }}</H3>
        </div>
    </div>
</template>

<script setup>
import { useStore } from '../store/cities'
import { $_getCityWeather, web_key } from '../apis/almap'
import { ref } from 'vue'
// 使用pinia
let cityWeather = useStore()
// 天气响应数据
let weatherData = ref({})
// 天气对应的图片
let weatherIcon = ref({})

$_getCityWeather({
    key: web_key, //之前拿到的key
    city: cityWeather.cityCode //城市的地理编码
}).then(res => {
    weatherData.value = res.data.lives[0]
    // 根据天气情况设置相应的图标URL
    switch(weatherData.value.weather){
        case '晴':
            weatherIcon.value = '../../public/imgs/sunday.jpg';
            break;
        case '阴' && '多云':
            weatherIcon.value = '../../public/imgs/red.jpg';
            break;
        case '雨':
            weatherIcon.value = '../../public/imgs/rain.jpg';
            break;
        default:
            weatherIcon.value = '../../public/imgs/defaut.jpg';
            break;
    }
    console.log(res);
})

</script>

因为后端给出的数据中没有图片,所以用了本地的图片来代替,通过Switch方法来渲染每一个城市所对应的天气和图片。之前这里用过if + includes的方法,只不过这个方法只能渲染出一张图片,再渲染时includes就报错了,有知道解决方法的小伙伴们可以评论哦!

实现效果图

点击A页面某一个城市,然后跳转到C页面就获取到该城市所对应的天气啦。

保姆级指南:Vue 3 + Pinia + Vue Router + 高德地图实现不同页面数据传递与效果展示

总结

该功能是基于vue3实现不同页面之间的数据的传递以及数据的渲染。功能比较简单实现也比较容易。有不足之处希望小伙伴们,批评指正。

转载自:https://juejin.cn/post/7261932861682286647
评论
请登录