本项目博客总结:【前端】Vue项目:旅游App-博客总结
在common.css中设置按钮的渐变色:
/* 渐变色 */
--theme-linear-gradient:linear-gradient(90deg,#fa8c1d,#fcaf3f);
html:
<div class="searchBtn">
开始搜索
div>
css:
.searchBtn{
display: flex;
justify-content: center;
align-items: center;
height: 38px;
font-size: 18px;
// 渐变色要用image
background-image:var(--theme-linear-gradient);
color: #fff;
border-radius: 20px;
margin: 20px 20px;
}
效果:
先写一个search.vue:
<template>
<div class="search">
<h2>searchh2>
div>
template>
<script setup>
script>
<style lang="less" scoped>
style>
注册路由:
{
path:'/search',
component:()=>import("@/views/search/search.vue")
}
在按钮的地方监听点击:
<div class="searchBtn" @click="searchBtnClick()">
开始搜索
div>
对应js:
import { useRouter } from 'vue-router'
const router = useRouter()
// 搜索按钮跳转
function searchBtnClick() {
router.push({
path:'/search'
})
}
到这里,点击了之后就可以跳转至search页面了。
一般来说,点击后的跳转会携带一些数据,我们这里用query
属性来携带数据。
在home.vue传送数据:
// 搜索按钮跳转
function searchBtnClick() {
router.push({
path:'/search',
query:{
// 因为是响应式
startDay:startDay.value,
endDay:endDay.value
}
})
}
在search页面用$route.query
显示数据:
<div class="search">
<h2>searchh2>
<h2>{{ $route.query.startDay }}
{{ $route.query.endDay }}h2>
div>
在之前的博客中我们写了两种隐藏TabBar的方法。前面用的是第二种,这里我们用第一种。
ps:两种方法都可以,工作中具体看哪种更方便就选哪种,这里只是练习。
在路由处设置meta:
{
path: '/search',
component: () => import("@/views/search/search.vue"),
meta: {
hideTabBar: true
}
}
在App.vue处增加v-if的判断:
<tab-bar v-if="!$route.meta.hideTabBar">tab-bar>
js:引入route
import { useRoute } from 'vue-router'
const route=useRoute()
效果:可以隐藏。
在本项目中已经进行了两次数据请求,因此具体步骤不再赘述。
接口:123.207.32.32:1888/api/home/categories
在service/home中:
export function getCategories() {
// request的index导出的是一个对象
return HYRequest.get({
// 参数也是一个对象
url: '/home/categories'
})
}
在store/home中:
const useHomeStore = defineStore('home', {
state: () => {
return {
hotSuggest: [],
categories:[]
}
},
actions: {
// 网络请求,由于返回一个promise,要异步async await
async fetchHotSuggest() {
const res = await getHotSuggest()
this.hotSuggest = res.data
// console.log(res)
},
async fetchCategories(){
const res = await getCategories()
this.categories = res.data
}
}
})
控制台输出一下数据:
home-categories组件:
<template>
<div class="home-categories">
<template v-for="(item, index) in categoriesData" :key="item.id">
<div class="item">
<img :src=item.pictureUrl alt="">
<div class="text">{{ item.title }}div>
div>
template>
div>
template>
<script setup>
import { storeToRefs } from 'pinia';
import useHomeStore from '../../../store/modules/home';
const homeStore = useHomeStore()
homeStore.fetchCategories()
const { categories } = storeToRefs(homeStore)
const categoriesData = categories
script>
<style lang="less" scoped>
style>
注意:让左右可以滚动但滚动条不显示的方法:
// 滚动条
overflow-x: auto;
// 滚动条不显示
&::-webkit-scrollbar {
display: none;
}
整体css:
.home-categories {
display: flex;
align-items: center;
padding: 0 20px;
margin-top: 20px;
margin-left: -10px;
margin-bottom: 10px;
height: 65px;
// 滚动条
overflow-x: auto;
// 滚动条不显示
&::-webkit-scrollbar {
display: none;
}
.item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 0 12px;
img {
width: 32px;
height: 32px;
}
.text {
height: 20px;
width: 56px;
text-align: center;
}
}
}
效果:
添加渐变色。
:root {
/* 渐变色 */
--theme-linear-gradient:linear-gradient(90deg,#fa8c1d,#fcaf3f);
}
添加search页面的路由。
{
path: '/search',
component: () => import("@/views/search/search.vue"),
meta: {
hideTabBar: true
}
}
添加对分类数据categories的网络请求。
export function getCategories() {
// request的index导出的是一个对象
return HYRequest.get({
// 参数也是一个对象
url: '/home/categories'
})
}
添加对分类数据categories的store数据存储。
// home.vue页面所有的进行网络请求和数据都封装到这里
import { defineStore } from "pinia";
import { getHotSuggest,getCategories } from '@/service'
const useHomeStore = defineStore('home', {
state: () => {
return {
hotSuggest: [],
categories:[]
}
},
actions: {
// 网络请求,由于返回一个promise,要异步async await
async fetchHotSuggest() {
const res = await getHotSuggest()
this.hotSuggest = res.data
// console.log(res)
},
async fetchCategories(){
const res = await getCategories()
this.categories = res.data
}
}
})
export default useHomeStore
封装了分类数据categories页面的组件。
<template>
<div class="home-categories">
<template v-for="(item, index) in categoriesData" :key="item.id">
<div class="item">
<img :src=item.pictureUrl alt="">
<div class="text">{{ item.title }}div>
div>
template>
div>
template>
<script setup>
import { storeToRefs } from 'pinia';
import useHomeStore from '../../../store/modules/home';
const homeStore = useHomeStore()
homeStore.fetchCategories()
const { categories } = storeToRefs(homeStore)
const categoriesData = categories
script>
<style lang="less" scoped>
.home-categories {
display: flex;
align-items: center;
padding: 0 20px;
margin-top: 20px;
margin-left: -10px;
margin-bottom: 10px;
height: 65px;
// 滚动条
overflow-x: auto;
// 滚动条不显示
&::-webkit-scrollbar {
display: none;
}
.item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 0 12px;
img {
width: 32px;
height: 32px;
}
.text {
height: 20px;
width: 56px;
text-align: center;
}
}
}
style>
增加了search和categories的显示。
<template>
<div class="home">
<div class="nav-bar">
<div class="title">旅游Appdiv>
<div class="banner">
<img src="@/assets/img/home/banner.webp" alt="">
div>
div>
<div class="search-box">
<div class="section location">
<div class="city">
<router-link to="/city">{{ cityStore.currentCity.cityName }}router-link>
div>
<div class="position">
<div class="text">我的位置div>
<img src="@/assets/img/home/icon_location.png" alt="">
div>
div>
<div class="section time-range" :value="date" @click="showCalendar = true">
<div class="start">
<span>入住span>
<div class="time">
{{ startDay }}
div>
div>
<div class="stay">共{{ date }}晚div>
<div class="end">
<span>离店span>
<div class="time">
{{ endDay }}
div>
div>
div>
<van-calendar :round="false" v-model:show="showCalendar" type="range" @confirm="onConfirm"
:show-confirm="false" />
<div class="price-counter section">
<div class="left">价格不限div>
<div class="right">人数不限div>
div>
<div class="keyword section">
<span>关键字/位置/民宿名span>
div>
<div class="hotSuggest section">
<template v-for="(item, index) in hotSuggestData" :key="index">
<div class="hotSuggestItem">
{{ item.tagText.text }}
div>
template>
div>
<div class="searchBtn" @click="searchBtnClick()">
开始搜索
div>
<homeCategories />
div>
div>
template>
<script setup>
import useCityStore from '../../store/modules/city';
import useHomeStore from '../../store/modules/home';
import { formatMonthDay, getDiffDate } from '@/utils/formatDate'
import { ref } from 'vue';
import { storeToRefs } from 'pinia';
import { useRouter } from 'vue-router'
import homeCategories from './cpns/home-categories.vue'
const cityStore = useCityStore()
const homeStore = useHomeStore()
const router = useRouter()
homeStore.fetchCategories()
const { categories } = storeToRefs(homeStore)
console.log(categories)
// 日期
const today = new Date()
const startDay = ref(formatMonthDay(today))
const endDay = ref(formatMonthDay(new Date().setDate(today.getDate() + 1))) //明天写法
// 日历
const date = ref('1');
const showCalendar = ref(false);
const formatDate = (date) => `${date.getMonth() + 1}/${date.getDate()}`;
const onConfirm = (values) => {
const [start, end] = values;
showCalendar.value = false;
startDay.value = formatMonthDay(start)
endDay.value = formatMonthDay(end)
date.value = getDiffDate(start, end)
};
// 热门数据
homeStore.fetchHotSuggest()
const { hotSuggest } = storeToRefs(homeStore)
const hotSuggestData = hotSuggest
// 搜索按钮跳转
function searchBtnClick() {
router.push({
path: '/search',
query: {
// 因为是响应式
startDay: startDay.value,
endDay: endDay.value
}
})
}
script>
<style lang="less" scoped>
.home {
.nav-bar {
.title {
height: 46px;
// flex居中,以后左右有东西可以直接加
display: flex;
align-items: center;
justify-content: center;
color: var(--primary-color);
font-size: 16px;
font-weight: 700;
}
.banner {
// 图片本身大很多,让它大小刚好
img {
width: 100%;
}
}
}
.search-box {
--van-calendar-popup-height: 100%;
// search-box里的每个部分都加上section
// 都有类似的样式
.section {
display: flex;
flex-wrap: wrap;
align-items: center;
padding: 0 20px;
color: #999;
margin-top: 10px;
}
.location {
height: 44px;
display: flex;
align-items: center;
padding: 0 20px;
color: #53565c;
.city {
// flex:1 === flex:1 1 auto 除了position之外的剩余部分都属于city
flex: 1;
}
.position {
width: 74px;
display: flex;
align-items: center;
.text {
font-size: 12px;
}
img {
width: 20px;
margin-left: 5px;
}
}
}
.time-range {
display: flex;
justify-content: space-between;
height: 45px;
span {
font-size: 16px;
}
.time {
color: #53565c;
}
}
.price-counter {
justify-content: space-between;
height: 35px;
}
.keyword {
height: 35px;
}
.hotSuggest {
.hotSuggestItem {
margin: 3px;
padding: 4px 8px;
font-size: 12px;
background-color: #f1f3f5;
color: #3f4954;
border-radius: 20px;
}
}
.searchBtn {
display: flex;
justify-content: center;
align-items: center;
height: 38px;
font-size: 18px;
// 渐变色要用image
background-image: var(--theme-linear-gradient);
color: #fff;
border-radius: 20px;
margin: 20px 20px;
}
}
}
style>
新增的页面,还没写内容。
<template>
<div class="search">
<h2>searchh2>
<h2>{{ $route.query.startDay }}
{{ $route.query.endDay }}h2>
div>
template>
<script setup>
script>
<style lang="less" scoped>
style>
增加了search的v-if判断是否显示TabBar。
<template>
<div class="app">
<router-view/>
<tab-bar v-if="!$route.meta.hideTabBar">tab-bar>
div>
template>
<script setup>
import tabBar from './components/tab-bar/tab-bar.vue';
import { useRoute } from 'vue-router'
const route=useRoute()
script>
<style lang="less" scoped>
style>
Pinia-学习之路 03,storeToRefs 及 改变数据状态 - 掘金 (juejin.cn)
overflow - CSS(层叠样式表) | MDN (mozilla.org)
::-webkit-scrollbar - CSS(层叠样式表) | MDN (mozilla.org)
【CSS】渐变背景(background-image)_妙趣前端的博客-CSDN博客_background-image 渐变