Vue利用flex布局实现TV端城市列表

本文介绍如何使用Vue和Flex布局实现电视端的城市列表及搜索功能,包括输入框聚焦、软键盘弹出、城市列表展示等细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Vue利用flex布局实现TV端城市列表

vue中城市列表和搜索很常见,这篇博客就来说说咋实现搜索和城市列表

1.实现搜索布局代码:

<div class="search-bar">
  <input class="search-input" v-model="citySearchResult" :placeholder="searchDefault" :key="searchTitle"
         @endEditing="endEditing" :focusable="true" ref="searchInput" :duplicateParentState="true"
         :enableFocusBorder="true"/>
  <img class="index-root-search-image-view-css" :src="searchIcon">
  <span class="index-root-search-text-view-css" ref="textViewCity">{{searchDefaultKeyWord}}</span>
</div>

2.搜索布局css样式代码:

.search-bar-root {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin-top: 140px;
}
​
.index-root-search-title-css {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin-bottom: 40px;
}
​
.search-bar-root .search-bar {
  background-color: #ffffff;
  width: 1000px;
  height: 100px;
  display: flex;
  justify-content: center;
  border-radius: 8px;
}
​
.search-input {
  width: 780px;
  border-radius: 8px;
  font-size: 36px;
  font-family: PingFangSC-Regular, PingFang SC;
  font-weight: 400;
  color: #000000;
  margin-left: 40px;
  text-indent: 40px;
}
​
.index-root-search-image-view-css {
  position: absolute;
  width: 32px;
  height: 32px;
  top: 35px;
  bottom: 35px;
  right: 0;
  margin-right: 102px;
  text-align: center;
}
​
.index-root-search-flex-view-css {
  display: flex;
  flex-wrap: wrap;
  flex-direction: row;
  width: 1450px;
  margin-left: 245px;
  margin-right: 245px;
  margin-top: 40px;
}
​
.index-root-search-text-view-css {
  font-size: 30px;
  font-family: PingFangSC-Regular, PingFang SC;
  color: #000000;
  text-align: center;
  font-weight: 400;
  top: 0;
  bottom: 0;
  right: 0;
  position: absolute;
  margin-right: 30px;
}
​
.index-root-search-title-text-view-css {
  font-size: 70px;
  font-family: PingFangSC-Regular, PingFang SC;
  color: #ffffff;
  text-align: center;
  opacity: 1.0;
}
​
.search-city-button-view-css {
  width: 270px;
  height: 100px;
  background-color: rgba(0, 0, 0, .1);
  margin-right: 20px;
  margin-top: 40px;
  border-radius: 11px;
  border-width: 2px;
  border-color: rgba(255, 255, 255, 0.1);
  focus-background-color: #fff;
}
​
.search-city-button-view-css .city-sel-box {
  border-width: 2px;
  border-color: #32C5FF;
}

3.城市列表布局代码:

<div class="index-root-search-flex-view-css" :clipChildren="false" ref="citySearch">
  <div class="search-city-button-view-css"
       v-for="(item,cityId) in hotCity" :focusable="true"
       :key="cityId"
       :ref="`hotRef${cityId}`" @focus="onFocus" :clipChildren="false">
    <div class="icon-location-reactive" ref="searchLocation" :duplicateParentState="true" style="visibility: visible;margin-right: 20px" v-if="showHot && cityId===0">
      <img src="@/assets/location.png" alt="" class="icon-location" showOnState="normal">
      <img src="@/assets/location_hot_focus.png" alt="" class="icon-location" showOnState="focused">
    </div>
    <span class="search-city-hot-text-iew-css" :duplicateParentState="true" showOnState="focused"
          ref="searchHotSelected"
          :style="{focusColor: focusHotTextColor,fontSize: textFontSize,fontWeight: textFontWeight,}">{{item.cityName}}</span>
  </div>

4.城市列表css样式代码:

.index-root-search-flex-view-css {
  display: flex;
  flex-wrap: wrap;
  flex-direction: row;
  width: 1450px;
  margin-left: 245px;
  margin-right: 245px;
  margin-top: 40px;
}
​
.index-root-search-text-view-css {
  font-size: 30px;
  font-family: PingFangSC-Regular, PingFang SC;
  color: #000000;
  text-align: center;
  font-weight: 400;
  top: 0;
  bottom: 0;
  right: 0;
  position: absolute;
  margin-right: 30px;
}
​
.index-root-search-title-text-view-css {
  font-size: 70px;
  font-family: PingFangSC-Regular, PingFang SC;
  color: #ffffff;
  text-align: center;
  opacity: 1.0;
}
​
.search-city-button-view-css {
  width: 270px;
  height: 100px;
  background-color: rgba(0, 0, 0, .1);
  margin-right: 20px;
  margin-top: 40px;
  border-radius: 11px;
  border-width: 2px;
  border-color: rgba(255, 255, 255, 0.1);
  focus-background-color: #fff;
}
​
.search-city-button-view-css .city-sel-box {
  border-width: 2px;
  border-color: #32C5FF;
}
​
.icon-location-reactive {
  position: absolute;
  width: 26px;
  height: 34px;
  margin-left: 60px;
  margin-top: 30px;
  margin-bottom: 30px;
}
​
.icon-location {
  width: 26px;
  height: 34px;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 9;
}
​
.search-city-hot-text-iew-css {
  width: 270px;
  height: 100px;
  background-color: rgba(50, 197, 255, 0.1);
  border-radius: 11px;
  border: 2px solid #32C5FF;
  font-size: 36px;
  font-family: PingFangSC-Regular, PingFang SC;
  text-align: center;
  color: white;
}
​
.search-city-empty {
  margin-top: 40px;
  width: 425px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  margin-left: 535px;
}
​
.search-city-empty .icon-no-connect {
  width: 425px;
  height: 307px;
}
​
.search-city-empty .empty-txt {
  font-size: 32px;
  font-family: PingFangSC-Light, PingFang SC;
  font-weight: 300;
  color: #FFFFFF;
  margin-top: 60px;
}

5.城市列表获取焦点的事件:

主要是在div设置:focusable="true"和@focus="onFocus"

<div class="search-city-button-view-css"
             v-for="(item,cityId) in hotCity" :focusable="true"
             :key="cityId"
             :ref="`hotRef${cityId}`" @focus="onFocus" :clipChildren="false">
          <div class="icon-location-reactive" ref="searchLocation" :duplicateParentState="true" style="visibility: visible;margin-right: 20px" v-if="showHot && cityId===0">
            <img src="@/assets/location.png" alt="" class="icon-location" showOnState="normal">
            <img src="@/assets/location_hot_focus.png" alt="" class="icon-location" showOnState="focused">
 </div>

6.设置焦点背景颜色和字体效果:

主要是设置:duplicateParentState="true"当文本获得焦点时颜色不受父布局影响,还可以设置焦点放大和带边框效果

:enableFocusBorder="true"//设置获得焦点时的边框
:focusScale="1.0"//设置焦点放大时的倍数

焦点效果的样式::style="{focusColor: focusHotTextColor,fontSize: textFontSize,fontWeight: textFontWeight,}

<span class="search-city-hot-text-iew-css" :duplicateParentState="true" showOnState="focused"
      ref="searchHotSelected"
      :style="{focusColor: focusHotTextColor,fontSize: textFontSize,fontWeight: textFontWeight,}">{{item.cityName}}</span>

7.搜索框输入事件:

//输入内容之后请求城市列表接口刷新数据
endEditing(e) {
  console.log("--resultData--", this.citySearchResult)
},

8.搜索框获取焦点的事件:

onFocus(e) {
  this.focused = e.isFocused;
  this.$emit("onButtonFocused", e.isFocused);
},

9.默认弹出TV软键盘:

mounted() {
  this.hotCity = hotCity;
  this.showHot = true;
  this.pageLoading = true
  //弹出软键盘
  this.$refs.searchInput.focus()
  //搜索框默认获取焦点
  this.setHideLoading()
},

10.完整代码如下:

<template>
  <div class="index-root-search-view-css" :clipChildren="false">
    <img class="search-background-view-css" :src="searchImageData"/>
    <div class="search-bar-root">
      <div class="index-root-search-title-css">
        <span class="index-root-search-title-text-view-css"> {{ searchTitle }}</span>
      </div>
      <div class="search-bar">
        <input class="search-input" v-model="citySearchResult" :placeholder="searchDefault" :key="searchTitle"
               @endEditing="endEditing" :focusable="true" ref="searchInput" :duplicateParentState="true"
               :enableFocusBorder="true"/>
        <img class="index-root-search-image-view-css" :src="searchIcon">
        <span class="index-root-search-text-view-css" ref="textViewCity">{{searchDefaultKeyWord}}</span>
      </div>
      <div class="index-root-search-flex-view-css" :clipChildren="false" ref="citySearch">
        <div class="search-city-button-view-css"
             v-for="(item,cityId) in hotCity" :focusable="true"
             :key="cityId"
             :ref="`hotRef${cityId}`" @focus="onFocus" :clipChildren="false">
          <div class="icon-location-reactive" ref="searchLocation" :duplicateParentState="true" style="visibility: visible;margin-right: 20px" v-if="showHot && cityId===0">
            <img src="@/assets/location.png" alt="" class="icon-location" showOnState="normal">
            <img src="@/assets/location_hot_focus.png" alt="" class="icon-location" showOnState="focused">
          </div>
          <span class="search-city-hot-text-iew-css" :duplicateParentState="true" showOnState="focused"
                ref="searchHotSelected"
                :style="{focusColor: focusHotTextColor,fontSize: textFontSize,fontWeight: textFontWeight,}">{{item.cityName}}</span>
        </div>
        <div class="search-city-empty" v-if="hotCity.length === 0">
          <img src="@/assets/no_content.png" alt="" class="icon-no-connect"/>
          <p class="empty-txt">没有搜索结果~</p>
        </div>
      </div>
    </div>
    <loading-view
        style="width: 100px;height: 100px;position: absolute;left:960px;right:960px;top:500px;bottom:500px;align-self:
        center;align-items: center;justify-content: center" v-show="pageLoading"/>
  </div>
</template>

<script>
import searchImage from "@/assets/search_focus.png";
import searchBackGroundImage from "@/assets/index-bg-qing.jpg";
import {hotCity} from '@/views/contsants';
import {ESLaunchManager} from "@extscreen/es-core";

export default {
  name: "city_list",
  props: {
    searchKeyWord: {
      type: String,
      default: '',
    },
    focusTextColor: {
      type: String,
      default: '#000000'
    },
    focusHotTextColor: {
      type: String,
      default: '#00EFFF'
    },
    textColor: {
      type: String,
      default: '#FFFFFF'
    },
    textFontSize: {
      type: String,
      default: '30px'
    },
    textFontWeight: {
      type: Number,
      default: 400
    },
    focusBackground: {
      orientation: 'TL_BR',//TOP_BOTTOM,TR_BL, RIGHT_LEFT, BR_TL, BOTTOM_TOP,BL_TR,LEFT_RIGHT,TL_BR,
      cornerRadius: [40, 40, 40, 40],
      normal: ['#00000000', '#00000000'],
      focused: ['#F5F5F5', '#F5F5F5'],
    },
  },
  data() {
    return {
      pageLoading: false,
      text: 'search city',
      search: '',
      searchIcon: searchImage,
      searchImageData: searchBackGroundImage,
      searchTitle: "切换城市",
      searchDefaultKeyWord: '搜索',
      searchDefault: '请输入城市名称首字母或全拼',
      focusColor: '#f5f5f5',
      citySearchResult: "",
      hotCity: [],
      cityName: "",
      cityId: "",
      showHot: true,
      params: '',
    }
  },
  activated() {
  },
  deactivated() {
    this.resetModel()
  },
  mounted() {
    this.hotCity = hotCity;
    this.showHot = true;
    this.pageLoading = true
    //弹出软键盘
    this.$refs.searchInput.focus()
    //搜索框默认获取焦点
    this.setHideLoading()
  },
  methods: {
    setHideLoading() {
      setTimeout(() => {
        this.pageLoading = false
      }, 500)
    },
    onFocus(e) {
      this.focused = e.isFocused;
      this.$emit("onButtonFocused", e.isFocused);
    },
    //输入内容之后请求城市
    endEditing(e) {
      console.log("--resultData--", this.citySearchResult)
    },
    onBackPressed() {
      ESLaunchManager.finishESPage();
    },
    resetModel() {
      this.citySearchResult = "";
      this.hotCity = [];
      this.pageLoading = false;
      this.searchTitle = "";
      this.searchDefaultKeyWord = "";
      this.searchDefault = "";
    },
  }
}
</script>

<style scoped>
.index-root-search-view-css {
  width: 1920px;
  height: 1080px;
  background-color: transparent;
}

.search-background-view-css {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  background-color: transparent;
}

.search-bar-root {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin-top: 140px;
}

.index-root-search-title-css {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin-bottom: 40px;
}

.search-bar-root .search-bar {
  background-color: #ffffff;
  width: 1000px;
  height: 100px;
  display: flex;
  justify-content: center;
  border-radius: 8px;
}

.search-input {
  width: 780px;
  border-radius: 8px;
  font-size: 36px;
  font-family: PingFangSC-Regular, PingFang SC;
  font-weight: 400;
  color: #000000;
  margin-left: 40px;
  text-indent: 40px;
}

.index-root-search-image-view-css {
  position: absolute;
  width: 32px;
  height: 32px;
  top: 35px;
  bottom: 35px;
  right: 0;
  margin-right: 102px;
  text-align: center;
}

.index-root-search-flex-view-css {
  display: flex;
  flex-wrap: wrap;
  flex-direction: row;
  width: 1450px;
  margin-left: 245px;
  margin-right: 245px;
  margin-top: 40px;
}

.index-root-search-text-view-css {
  font-size: 30px;
  font-family: PingFangSC-Regular, PingFang SC;
  color: #000000;
  text-align: center;
  font-weight: 400;
  top: 0;
  bottom: 0;
  right: 0;
  position: absolute;
  margin-right: 30px;
}

.index-root-search-title-text-view-css {
  font-size: 70px;
  font-family: PingFangSC-Regular, PingFang SC;
  color: #ffffff;
  text-align: center;
  opacity: 1.0;
}

.search-city-button-view-css {
  width: 270px;
  height: 100px;
  background-color: rgba(0, 0, 0, .1);
  margin-right: 20px;
  margin-top: 40px;
  border-radius: 11px;
  border-width: 2px;
  border-color: rgba(255, 255, 255, 0.1);
  focus-background-color: #fff;
}

.search-city-button-view-css .city-sel-box {
  border-width: 2px;
  border-color: #32C5FF;
}

.icon-location-reactive {
  position: absolute;
  width: 26px;
  height: 34px;
  margin-left: 60px;
  margin-top: 30px;
  margin-bottom: 30px;
}

.icon-location {
  width: 26px;
  height: 34px;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 9;
}

.search-city-hot-text-iew-css {
  width: 270px;
  height: 100px;
  background-color: rgba(50, 197, 255, 0.1);
  border-radius: 11px;
  border: 2px solid #32C5FF;
  font-size: 36px;
  font-family: PingFangSC-Regular, PingFang SC;
  text-align: center;
  color: white;
}

.search-city-empty {
  margin-top: 40px;
  width: 425px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  margin-left: 535px;
}

.search-city-empty .icon-no-connect {
  width: 425px;
  height: 307px;
}

.search-city-empty .empty-txt {
  font-size: 32px;
  font-family: PingFangSC-Light, PingFang SC;
  font-weight: 300;
  color: #FFFFFF;
  margin-top: 60px;
}
</style>

11.实现的效果截图如下:

 

请将该vue项目中的响应式布局调整为可以自适应各个打开屏幕大小尺寸的方法:<template> <!-- 体验页面 --> <div class="experience"> <!-- 顶部导航栏 --> <NavBar /> <div class="container"> <!-- 首图内容区域 --> <div class="content-banner"></div> <div class="content-wrapper"> <!-- 商务之旅 --> <div class="business margin-top-50"> <div class="img-box"> <responsive-image class="hd01" :small-image="hd01.smallImage1" :medium-image="hd01.mediumImage1" :large-image="hd01.largeImage1" alt-text="Description of image" /> <!-- <img src="../../assets/experience/hd-01.png" alt="" /> --> </div> <div class="text-box"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t('Business') }}</p> <p class="content margin-top-20" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t('text7') }} </p> <p class="more" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t("more14") }} </p> </div> </div> <!-- 旅游度假 --> <div class="tourism margin-top-50"> <div class="text-box"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('trip') }}</p> <p class="content margin-top-20" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t('text8') }} </p> <p class="more" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t("more15") }} </p> </div> <div class="img-box"> <responsive-image class="hd02" :small-image="hd02.smallImage2" :medium-image="hd02.mediumImage2" :large-image="hd02.largeImage2" alt-text="Description of image" /> <!-- <img src="../../assets/experience/hd-02.png" alt="" /> --> </div> </div> </div> <!-- 查看客房 --> <div class="content-swiper"> <div class="content-kefang"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('Guest') }}</p> <!-- 轮播图 --> <div class="foot-swiper-box margin-top-50"> <RoomSwiper :bannerList="roomBannerList" /> </div> </div> <div class="content-kefang"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('Apartment') }}</p> <!-- 轮播图 --> <div class="foot-swiper-box margin-top-50"> <RoomSwiper :bannerList="apartBannerList" /> </div> </div> <div class="device"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('Facilities') }}</p> <div class="device-content margin-top-50"> <div class="img-box"> <img src="../../assets/experience/hd-01.png" alt="" /> </div> <div class="text-box"> <ul class="device-list"> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('WiFi') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('individually') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('TV') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('laundry') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('safes') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('coffee') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('Minibar') }}</li> </ul> </div> </div> </div> </div> </div> <!-- 滚动宣传图文本页面 --> <!-- <div v-for="item in roomBannerList" :key="item.id"> <h2>{{ $t(item.titleKey) }}</h2> <p>{{ $t(item.promptKey) }}</p> </div> --> <!-- 底部导航栏 --> <Footer /> </div> </template> <script> import RoomSwiper from "@/components/swiper/RoomSwiper.vue"; export default { name: "experience", components: { RoomSwiper, }, data() { return { msg: "Welcome to Your Vue.js App", // 响应式图片数据 hd01: { smallImage1: require("../../assets/experience/hd-01-mobile.jpg"), mediumImage1: require("../../assets/experience/hd-01.png"), largeImage1: require("../../assets/experience/hd-01.png"), }, hd02: { smallImage2: require("../../assets/experience/hd-02-mobile.jpg"), mediumImage2: require("../../assets/experience/hd-02.png"), largeImage2: require("../../assets/experience/hd-02.png"), }, roomBannerList: [ { id: 1, imgUrl: require("../../assets/room/room-01.png"), title: "豪华套房", prompt: "尊享私人空间,尽享奢华体验", }, { id: 2, imgUrl: require("../../assets/room/room-02.png"), title: "豪华楼层/豪华雅致大床房", prompt: "面积约为42平方米,装饰现代,舒适典雅。卧室和大理石浴室设气派的落地窗玻璃,可以俯瞰草原城市胜景或乌兰木伦湖滨美景。", }, { id: 3, imgUrl: require("../../assets/room/room-03.png"), title: "豪华双床房", prompt: "面积约为42平方米,装饰现代,舒适典雅。卧室和大理石浴室设气派的落地窗玻璃,可以俯瞰草原城市胜景或乌兰木伦湖滨美景。", }, ], apartBannerList: [ { id: 1, imgUrl: require("../../assets/room/room-01.png"), title: "豪华套房", prompt: "尊享私人空间,尽享奢华体验", }, { id: 2, imgUrl: require("../../assets/room/room-02.png"), title: "豪华楼层/豪华雅致大床房", prompt: "面积约为42平方米,装饰现代,舒适典雅。卧室和大理石浴室设气派的落地窗玻璃,可以俯瞰草原城市胜景或乌兰木伦湖滨美景。", }, { id: 3, imgUrl: require("../../assets/room/room-03.png"), title: "豪华双床房", prompt: "面积约为42平方米,装饰现代,舒适典雅。卧室和大理石浴室设气派的落地窗玻璃,可以俯瞰草原城市胜景或乌兰木伦湖滨美景。", }, ], }; }, }; </script> <style scoped> .content-banner { width: 100vw; height: 60rem; background-image: url("../../assets/banner/banner-04.jpg"); background-size: 100% 100%; position: relative; } .content-wrapper { max-width: 1920px; /* 限制最大宽度 */ margin: 0 auto; padding: 0 4rem; /* 添加基础内边距 */ } /* 优化商务/度假模块 */ .business, .tourism { display: grid; grid-template-columns: 1fr 1fr; gap: 6rem; align-items: center; padding: 8rem 0; max-width: 1600px; /* 限制最大内容宽度 */ } .title-en { font-size: 3rem; color: rgb(202, 171, 98); font-weight: bold; line-height: 2em; font-family: "Times New Roman", Times, serif; } .title-zh { font-size: 3.6rem; color: rgb(202, 171, 98); text-align: left; } .content { font-size: clamp(1.6rem, 2vw, 2.2rem); /* 响应式字体 */ line-height: 1.8; margin: 3rem 0; font-family: "Fangsong"; } /* 图片容器优化 */ .img-box { width: 100%; max-width: 800px; /* 限制最大宽度 */ margin: 0 auto; transition: transform 0.3s; } .img-box:hover { transform: scale(1.02); /* 添加悬停效果 */ } /* 文本区域优化 */ .text-box { max-width: 600px; margin: 0 auto; } .more { width: 10rem; font-size: 1.6rem; line-height: 2em; color: rgb(202, 171, 98); text-align: center; cursor: pointer; background-color: rgb(238, 235, 235); } /* 通用属性 */ /* 文本居中 */ .text-center { text-align: center; } /* div居中 */ .div-center { margin: 2rem auto; } /* 上外边距2rem */ .margin-top-20 { margin-top: 2rem; } /* 上外边距5rem */ .margin-top-50 { margin-top: 5rem; } /* 下外边距2rem */ .margin-bottom-20 { margin-bottom: 2rem; } /* 度假旅行 */ /* .tourism { width: 120rem; margin: 0 auto; display: flex; justify-content: space-between; margin-bottom: 10rem; } */ /* 查看客房 */ .content-kefang { width: 100vw; height: 75rem; } /* 客房设施 */ .device-content { display: grid; grid-template-columns: 1fr 1fr; gap: 8rem; max-width: 1400px; margin: 8rem auto; align-items: center; } .device-list { columns: 2; /* 增加列数 */ column-gap: 4rem; font-size: clamp(1.6rem, 1.8vw, 2rem); } .device { width: 100rem; margin: 0 auto; display: flex; flex-direction: column; align-items: center; justify-content: center; margin-bottom: 10rem; } .textEn { font-family: "Times New Roman", Times, serif !important; } /* 新增响应式断点 */ @media screen and (min-width: 1025px) { .content-banner { height: 50vh; } .business, .tourism { grid-template-columns: 55% 45%; /* 调整比例 */ } } /* 1024px以下 */ @media screen and (max-width: 1024px) { .content-banner { height: 70rem; } .business, .tourism { grid-template-columns: 1fr; gap: 4rem; padding: 4rem 0; } .content-wrapper { width: 160rem; } .title-en { font-size: 4.8rem; } .title-zh { font-size: 5.6rem; } .content { width: 74rem; font-size: 3rem; } .img-box { max-width: 100%; height: auto; } .more { width: 15rem; font-size: 2rem; } .device-content { grid-template-columns: 1fr; gap: 4rem; } /* .device-content { width: 100rem; margin: 10rem auto; display: flex; margin-bottom: 1rem; } */ .device-list { columns: 1; } .device { width: 100rem; margin: 0 auto; display: flex; flex-direction: column; align-items: center; justify-content: center; margin-bottom: 10rem; } } @media screen and (max-width: 768px) { .content-banner { height: 82rem; background-image: url("../../assets/banner/banner-04-mobile.jpg"); } .business { flex-direction: column; align-items: center; } .tourism { flex-direction: column; align-items: center; } .content-wrapper { padding: 0 2rem; } .img-box { order: 2; } .text-box { order: 1; } .title-en { font-size: 6rem; } .title-zh { font-size: 6.2rem; } .content { font-size: 1.8rem; } .img-box { width: 110rem; height: 60rem; margin-top: 5rem; margin-bottom: 2rem; } .more { width: 20rem; font-size: 2.4rem; margin-bottom: 5rem; margin-left: 80rem; } .device-content { width: 120rem; margin: 10rem auto; display: flex; margin-bottom: 1rem; flex-direction: row; margin-right: 10rem; } .device-list { font-size: 1.6rem; } .device { width: 150rem; margin: 0 auto; display: flex; flex-direction: column; align-items: center; justify-content: center; margin-bottom: 10rem; margin-right: 10rem; } } </style>
07-05
请帮我完善该vue项目下的响应式,使其网页设计的可以像香格里拉酒店官网一样简洁美观,<template> <!-- 体验页面 --> <div class="experience"> <!-- 顶部导航栏 --> <NavBar /> <div class="container"> <!-- 首图内容区域 --> <div class="content-banner"></div> <div class="content-wrapper"> <!-- 商务之旅 --> <div class="business margin-top-50"> <div class="img-box"> <responsive-image class="hd01" :small-image="hd01.smallImage1" :medium-image="hd01.mediumImage1" :large-image="hd01.largeImage1" alt-text="Description of image" /> <!-- <img src="../../assets/experience/hd-01.png" alt="" /> --> </div> <div class="text-box"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t('Business') }}</p> <p class="content margin-top-20" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t('text7') }} </p> <p class="more" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t("more14") }} </p> </div> </div> <!-- 旅游度假 --> <div class="tourism margin-top-50"> <div class="text-box"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('trip') }}</p> <p class="content margin-top-20" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t('text8') }} </p> <p class="more" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t("more15") }} </p> </div> <div class="img-box"> <responsive-image class="hd02" :small-image="hd02.smallImage2" :medium-image="hd02.mediumImage2" :large-image="hd02.largeImage2" alt-text="Description of image" /> <!-- <img src="../../assets/experience/hd-02.png" alt="" /> --> </div> </div> </div> <!-- 查看客房 --> <div class="content-swiper"> <div class="content-kefang"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('Guest') }}</p> <!-- 轮播图 --> <div class="foot-swiper-box margin-top-50"> <RoomSwiper :bannerList="roomBannerList" /> </div> </div> <div class="content-kefang"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('Apartment') }}</p> <!-- 轮播图 --> <div class="foot-swiper-box margin-top-50"> <RoomSwiper :bannerList="apartBannerList" /> </div> </div> <div class="device"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('Facilities') }}</p> <div class="device-content margin-top-50"> <div class="img-box"> <img src="../../assets/experience/hd-01.png" alt="" /> </div> <div class="text-box"> <ul class="device-list"> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('WiFi') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('individually') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('TV') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('laundry') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('safes') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('coffee') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('Minibar') }}</li> </ul> </div> </div> </div> </div> </div> <!-- 滚动宣传图文本页面 --> <!-- <div v-for="item in roomBannerList" :key="item.id"> <h2>{{ $t(item.titleKey) }}</h2> <p>{{ $t(item.promptKey) }}</p> </div> --> <!-- 底部导航栏 --> <Footer /> </div> </template> <script> import RoomSwiper from "@/components/swiper/RoomSwiper.vue"; export default { name: "experience", components: { RoomSwiper, }, data() { return { msg: "Welcome to Your Vue.js App", // 响应式图片数据 hd01: { smallImage1: require("../../assets/experience/hd-01-mobile.jpg"), mediumImage1: require("../../assets/experience/hd-01.png"), largeImage1: require("../../assets/experience/hd-01.png"), }, hd02: { smallImage2: require("../../assets/experience/hd-02-mobile.jpg"), mediumImage2: require("../../assets/experience/hd-02.png"), largeImage2: require("../../assets/experience/hd-02.png"), }, roomBannerList: [ { id: 1, imgUrl: require("../../assets/room/room-01.png"), title: "豪华套房", prompt: "尊享私人空间,尽享奢华体验", }, { id: 2, imgUrl: require("../../assets/room/room-02.png"), title: "豪华楼层/豪华雅致大床房", prompt: "面积约为42平方米,装饰现代,舒适典雅。卧室和大理石浴室设气派的落地窗玻璃,可以俯瞰草原城市胜景或乌兰木伦湖滨美景。", }, { id: 3, imgUrl: require("../../assets/room/room-03.png"), title: "豪华双床房", prompt: "面积约为42平方米,装饰现代,舒适典雅。卧室和大理石浴室设气派的落地窗玻璃,可以俯瞰草原城市胜景或乌兰木伦湖滨美景。", }, ], apartBannerList: [ { id: 1, imgUrl: require("../../assets/room/room-01.png"), title: "豪华套房", prompt: "尊享私人空间,尽享奢华体验", }, { id: 2, imgUrl: require("../../assets/room/room-02.png"), title: "豪华楼层/豪华雅致大床房", prompt: "面积约为42平方米,装饰现代,舒适典雅。卧室和大理石浴室设气派的落地窗玻璃,可以俯瞰草原城市胜景或乌兰木伦湖滨美景。", }, { id: 3, imgUrl: require("../../assets/room/room-03.png"), title: "豪华双床房", prompt: "面积约为42平方米,装饰现代,舒适典雅。卧室和大理石浴室设气派的落地窗玻璃,可以俯瞰草原城市胜景或乌兰木伦湖滨美景。", }, ], }; }, }; </script> <style scoped> .content-banner { width: 100vw; height: 72rem; background-image: url("../../assets/banner/banner-02.png"); background-size: 100% 100%; } .business { width: 130rem; margin: 0 auto; display: flex; justify-content: space-between; margin-bottom:10rem; } .title-en, .title-zh { font-size: 3.6rem; color: rgb(202, 171, 98); text-align: left; } .content { width: 60rem; font-size: 2rem; line-height: 2; font-family: "Fangsong"; text-align: justify; } .img-box { width: 50rem; height: 30rem; } .more { width: 15rem; font-size: 2rem; line-height: 2em; color: rgb(202, 171, 98); text-align: center; cursor: pointer; background-color: rgb(238, 235, 235); } /* 通用属性 */ /* 文本居中 */ .text-center { text-align: center; } /* div居中 */ .div-center { margin: 2rem auto; } /* 上外边距2rem */ .margin-top-20 { margin-top: 2rem; } /* 上外边距5rem */ .margin-top-50 { margin-top: 5rem; } /* 下外边距2rem */ .margin-bottom-20 { margin-bottom: 2rem; } /* 度假旅行 */ .tourism { width: 120rem; margin: 0 auto; display: flex; justify-content: space-between; margin-bottom: 10rem; } /* 查看客房 */ .content-kefang { width: 100vw; height: 85rem; } /* 客房设施 */ .device-content { width: 100rem; margin: 10rem auto; display: flex; margin-bottom: 1rem; } .device-list { margin-left: 2rem; font-size: 2rem; text-align: left; line-height: 2em; font-family: 'FangSong'; } .device { width: 100rem; margin: 0 auto; display: flex; flex-direction: column; align-items: center; justify-content: center; margin-bottom: 10rem; } .textEn { font-family: "Times New Roman", Times, serif !important; } /* 1024px以下 */ @media screen and (max-width: 1024px) { .content-banner { height: 70rem; } .business { flex-direction: column; align-items: center; } .tourism { flex-direction: column; align-items: center; } .content-wrapper { width: 160rem; } .title-en { font-size: 4.8rem; } .title-zh { font-size: 5.6rem; } .content { width: 74rem; font-size: 3rem; } .img-box{ width: 74rem; height: 42rem; } .more { width: 20rem; font-size: 2.4rem; } } .device-content { width: 100rem; margin: 10rem auto; display: flex; margin-bottom: 1rem; } .device-list { margin-left: 2rem; font-size: 2rem; text-align: left; line-height: 2em; font-family: 'FangSong'; } .device { width: 100rem; margin: 0 auto; display: flex; flex-direction: column; align-items: center; justify-content: center; margin-bottom: 10rem; } @media screen and (max-width: 768px) { .content-banner { height: 82rem; background-image: url("../../assets/banner/banner-02-mobile.jpg"); } .business { flex-direction: column; align-items: center; } .tourism { flex-direction: column; align-items: center; } .content-wrapper { width: 190rem; } .img-box { order: 2; } .text-box { order: 1; } .title-en { font-size: 6rem; } .title-zh { font-size: 6.2rem; } .content { width: 160rem; font-size: 4rem; } .img-box { width: 110rem; height: 60rem; } .more { width: 30rem; font-size: 3.2rem; margin-bottom: 5rem; margin-left: 80rem; } } .device-content { width: 120rem; margin: 10rem auto; display: flex; margin-bottom: 1rem; flex-direction: row; margin-right: 10rem; } .device-list { margin-left: 10rem; font-size: 2rem; text-align: left; line-height: 2em; font-family: 'FangSong'; margin-right: 10rem; } .device { width: 150rem; margin: 0 auto; display: flex; flex-direction: column; align-items: center; justify-content: center; margin-bottom: 10rem; margin-right: 10rem; } </style>
06-14
请帮我完善该vue项目在不同分辨率下的响应式设计,要求参考香格里拉酒店官网页面的设计风格:<template> <!-- 体验页面 --> <div class="experience"> <!-- 顶部导航栏 --> <NavBar /> <div class="container"> <!-- 首图内容区域 --> <div class="content-banner"></div> <div class="content-wrapper"> <!-- 商务接待 --> <div class="business margin-top-50"> <div class="img-box"> <responsive-image class="hd01" :small-image="hd01.smallImage1" :medium-image="hd01.mediumImage1" :large-image="hd01.largeImage1" alt-text="Description of image" /> <!-- <img src="../../assets/experience/hd-01.png" alt="" /> --> </div> <div class="text-box"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t('Business') }}</p> <p class="content margin-top-20" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t('text7') }} </p> <p class="more" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t("more14") }} </p> </div> </div> <!-- 度假之行 --> <div class="tourism margin-top-50"> <div class="text-box"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('trip') }}</p> <p class="content margin-top-20" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t('text8') }} </p> <p class="more" :class="{ textEn: $i18n.locale === 'en' }"> {{ $t("more15") }} </p> </div> <div class="img-box"> <responsive-image class="hd02" :small-image="hd02.smallImage2" :medium-image="hd02.mediumImage2" :large-image="hd02.largeImage2" alt-text="Description of image" /> <!-- <img src="../../assets/experience/hd-02.png" alt="" /> --> </div> </div> </div> <!-- 查看客房 --> <div class="content-swiper"> <div class="content-kefang"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('Guest') }}</p> <!-- 轮播图 --> <div class="foot-swiper-box margin-top-50"> <RoomSwiper :bannerList="roomBannerList" /> </div> </div> <div class="content-kefang"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('Apartment') }}</p> <!-- 轮播图 --> <div class="foot-swiper-box margin-top-50"> <RoomSwiper :bannerList="apartBannerList" /> </div> </div> <!-- 客房设施 --> <div class="device"> <p class="title-zh text-center" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('Facilities') }}</p> <div class="device-content margin-top-50"> <div class="img-box"> <img src="../../assets/experience/hd-01.png" alt="" /> </div> <div class="text-box"> <ul class="device-list"> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('WiFi') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('individually') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('TV') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('laundry') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('safes') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('coffee') }}</li> <li class="text" :class="{ textEn: $i18n.locale === 'en' }">{{ $t('Minibar') }}</li> </ul> </div> </div> </div> </div> </div> <!-- 底部导航栏 --> <Footer /> </div> </template> <script> import RoomSwiper from "@/components/swiper/RoomSwiper.vue"; export default { name: "experience", components: { RoomSwiper, }, data() { return { msg: "Welcome to Your Vue.js App", // 响应式图片数据 hd01: { smallImage1: require("../../assets/experience/hd-01-mobile.jpg"), mediumImage1: require("../../assets/experience/hd-01.png"), largeImage1: require("../../assets/experience/hd-01.png"), }, hd02: { smallImage2: require("../../assets/experience/hd-02-mobile.jpg"), mediumImage2: require("../../assets/experience/hd-02.png"), largeImage2: require("../../assets/experience/hd-02.png"), }, roomBannerList: [ { id: 1, imgUrl: require("../../assets/room/room-01.png"), title: "豪华套房", prompt: "尊享私人空间,尽享奢华体验", }, { id: 2, imgUrl: require("../../assets/room/room-02.png"), title: "豪华楼层/豪华雅致大床房", prompt: "面积约为42平方米,装饰现代,舒适典雅。卧室和大理石浴室设气派的落地窗玻璃,可以俯瞰草原城市胜景或乌兰木伦湖滨美景。", }, { id: 3, imgUrl: require("../../assets/room/room-03.png"), title: "豪华双床房", prompt: "面积约为42平方米,装饰现代,舒适典雅。卧室和大理石浴室设气派的落地窗玻璃,可以俯瞰草原城市胜景或乌兰木伦湖滨美景。", }, ], apartBannerList: [ { id: 1, imgUrl: require("../../assets/room/room-01.png"), title: "豪华套房", prompt: "尊享私人空间,尽享奢华体验", }, { id: 2, imgUrl: require("../../assets/room/room-02.png"), title: "豪华楼层/豪华雅致大床房", prompt: "面积约为42平方米,装饰现代,舒适典雅。卧室和大理石浴室设气派的落地窗玻璃,可以俯瞰草原城市胜景或乌兰木伦湖滨美景。", }, { id: 3, imgUrl: require("../../assets/room/room-03.png"), title: "豪华双床房", prompt: "面积约为42平方米,装饰现代,舒适典雅。卧室和大理石浴室设气派的落地窗玻璃,可以俯瞰草原城市胜景或乌兰木伦湖滨美景。", }, ], }; }, }; </script> <style scoped> /* 全局响应式设置 */ .experience { width: 100%; overflow-x: hidden; } .container { width: 100%; max-width: 2560px; margin: 0 auto; } /* 顶部横幅区域 */ .content-banner { width: 100%; height: 50vh; /* 使用视口高度 */ min-height: 300px; /* 最小高度 */ max-height: 600px; /* 最大高度 */ background-image: url("../../assets/banner/banner-04.jpg"); background-size: cover; background-position: center; background-repeat: no-repeat; } /* 内容区域 */ .content-wrapper { width: 90%; max-width: 1400px; margin: 0 auto; padding: 4rem 0; } /* 商务/旅游模块 - 响应式网格布局 */ .business, .tourism { display: grid; grid-template-columns: repeat(2, 1fr); gap: 4rem; align-items: center; margin: 6rem 0; } /* 文本区域 */ .text-box { flex: 1 1 45%; /* 基础宽度45% */ min-width: 300px; /* 最小宽度 */ } .title-zh { font-size: clamp(2.4rem, 3.5vw, 3.6rem); /* 响应式字体 */ color: rgb(202, 171, 98); margin-bottom: 2rem; } .content { font-size: clamp(1.6rem, 2vw, 2rem); line-height: 1.8; margin: 2rem 0; font-family: "Fangsong"; } .more { display: inline-block; padding: 1rem 2.5rem; font-size: clamp(1.4rem, 1.8vw, 1.6rem); color: rgb(202, 171, 98); background-color: rgb(238, 235, 235); border-radius: 4px; cursor: pointer; transition: all 0.3s ease; } .more:hover { background-color: #e0dcdc; transform: translateY(-2px); } /* 新增底部导航适配 */ .footer { width: 100%; margin-top: auto; /* 确保底部固定 */ } /* 优化视口单位使用 */ :root { --vh: 1vh; } /* 强制图片覆盖容器 */ .responsive-image img { position: absolute; width: 100%; height: 100%; object-fit: cover; /* 关键属性:保持比例填充 */ object-position: center; font-family: 'object-fit: cover'; /* 兼容旧版浏览器 */ } /* 图片容器基础样式强化 */ .img-box { height: auto; max-height: 400px; overflow: hidden; } .img-box img { width: 100%; height: auto; } .img-box:hover img { transform: scale(1.03); } /* 轮播图区域 */ .content-swiper { width: 90%; max-width: 1400px; margin: 0 auto; padding: 4rem 0; } .content-kefang { margin-bottom: 6rem; } .foot-swiper-box { margin-top: 3rem; } /* 设施区域 */ .device { margin-top: 2rem; } .device-content { display: grid; grid-template-columns: repeat(2, 1fr); gap: 4rem; align-items: center; margin-top: 4rem; } .device-list { display: grid; grid-template-columns: repeat(2, 1fr); gap: 2rem; font-size: clamp(1.6rem, 1.8vw, 1.8rem); line-height: 1.8; } .device-list li { position: relative; padding-left: 1rem; } /* 通用类 */ .text-center { text-align: center; } .textEn { font-family: "Times New Roman", Times, serif !important; } /* 新增4K屏幕适配样式 */ @media screen and (min-width: 2560px) { /* 主容器扩展 */ .content-wrapper, .content-swiper { width: 80%; max-width: 2200px; } /* 首图区域优化 */ .content-banner { height: 50vh; /* 全视口高度 */ min-height: 900px; } /* 商务/旅游模块优化 */ .business, .tourism { grid-template-columns: repeat(2, 1fr); gap: 6rem; align-items: stretch; /* 垂直拉伸 */ } /* 文本区域优化 */ .text-box { flex: 1 1 48%; /* 增加基础宽度 */ min-width: 400px; } /* 字体大小增强 */ .title-zh { font-size: clamp(3rem, 4.5vw, 5rem); } .content { font-size: clamp(1.8rem, 2.8vw, 3rem); } .more { font-size: clamp(1.6rem, 2.2vw, 2.4rem); padding: 1.5rem 3rem; } /* 设施列表优化 */ .device-list { grid-template-columns: repeat(3, 1fr); font-size: clamp(1.8rem, 2vw, 2.2rem); } } /* 新增4K+超宽屏适配 */ @media screen and (min-width: 3000px) { .content-wrapper, .content-swiper { width: 90%; max-width: 2800px; } .business, .tourism { gap: 8rem; } .content-banner { background-size: contain; /* 保持背景完整 */ } .device-list { grid-template-columns: repeat(4, 1fr); } } /* 优化现有媒体查询 */ @media screen and (max-width: 1024px) { .content-banner { height: 60vh; } .business, .tourism { gap: 3rem; } } @media screen and (max-width: 768px) { .content-banner { height: 50vh; background-image: url("../../assets/banner/banner-04-mobile.jpg"); } .business, .tourism { grid-template-columns: 1fr; } } </style>
最新发布
07-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值