当前位置: 首页 > news >正文

【HarmonyOS开发】通过媒体查询,实现一次开发,多端部署

 媒体查询(Media Queries)是一种在CSS中使用的技术,用于根据设备的特性和属性(如屏幕宽度、设备类型等)来应用不同的样式规则。通过媒体查询,可以根据不同的设备或屏幕尺寸为用户提供优化的布局和样式。

1、Web中CSS的媒体查询

1.1 根据屏幕宽度应用样式

@media screen and (max-width: 768px) {/* 当屏幕宽度小于等于 768px 时应用的样式 *//* 适用于移动设备或小屏幕 */
}@media screen and (min-width: 769px) and (max-width: 1024px) {/* 当屏幕宽度在 769px 到 1024px 之间时应用的样式 *//* 适用于平板设备或中等屏幕 */
}@media screen and (min-width: 1025px) {/* 当屏幕宽度大于等于 1025px 时应用的样式 *//* 适用于桌面设备或大屏幕 */
}

1.2 根据设备类型应用样式

@media screen and (orientation: landscape) {/* 当设备处于横向(landscape)方向时应用的样式 */
}@media screen and (orientation: portrait) {/* 当设备处于纵向(portrait)方向时应用的样式 */
}@media print {/* 在打印时应用的样式 */
}

1.3 组合多个条件的媒体查询

@media screen and (min-width: 768px) and (max-width: 1024px),(orientation: portrait) {/* 当屏幕宽度在 768px 到 1024px 之间或设备处于纵向方向时应用的样式 */
}

2、Web中JS的媒体查询

可以使用window.matchMedia()方法来执行媒体查询,并根据查询结果执行相应的操作。这个方法返回一个MediaQueryList对象,该对象具有matches属性,表示查询是否匹配。将查询的结果存储在Window全局变量即可。

// 创建一个媒体查询对象
var mediaQuery = window.matchMedia('(max-width: 768px)');// 检查媒体查询的匹配状态
if (mediaQuery.matches) {// 当媒体查询匹配时执行的操作// 适用于移动设备或小屏幕console.log('Media query matches!');
} else {// 当媒体查询不匹配时执行的操作// 适用于平板设备或大屏幕console.log('Media query does not match!');
}// 添加一个媒体查询监听器
mediaQuery.addListener(function(mediaQueryList) {if (mediaQueryList.matches) {// 当媒体查询匹配时执行的操作console.log('Media query matches!');} else {// 当媒体查询不匹配时执行的操作console.log('Media query does not match!');}
});

3、Vue/React中的媒体查询

3.1 Vue中使用媒体查询

3.1.1 计算属性

<template><div :class="containerClass"><p>Content goes here</p></div>
</template><script>
import { ref, onMounted, onUnmounted } from 'vue';export default {setup() {const containerClass = ref('');const updateContainerClass = () => {containerClass.value = window.innerWidth < 768 ? 'small-screen' : 'large-screen';};onMounted(() => {updateContainerClass();window.addEventListener('resize', updateContainerClass);});onUnmounted(() => {window.removeEventListener('resize', updateContainerClass);});return {containerClass};}
};
</script><style>
.small-screen {/* 在小屏幕上应用的样式 */
}.large-screen {/* 在大屏幕上应用的样式 */
}
</style>

3.1.2 三方库(vue-mq)

  • vue-mq(以这个为例)
  • vue-breakpoint-component
  • vue-responsive
  • vue-media-query-mixin
npm install vue-mq
// main.js中配置
import { createApp } from 'vue';
import App from './App.vue';
import VueMq from 'vue-mq';const app = createApp(App);app.use(VueMq, {breakpoints: {mobile: 768,tablet: 1024,desktop: 1280,// 根据需要添加其他断点}
});app.mount('#app');
// 使用
<template><div :class="$mq"><p>Content goes here</p></div>
</template><style>
.mobile {/* 在移动设备上应用的样式 */
}.tablet {/* 在平板设备上应用的样式 */
}.desktop {/* 在桌面设备上应用的样式 */
}
</style>

3.2 React中使用媒体查询(三方库)

  • react-responsive(以这个为主)
  • react-responsive-hooks
  • react-media
  • react-match-media
import React from 'react';
import styles from './MyComponent.module.css';
import { useMediaQuery } from 'react-responsive';const MyComponent = () => {const isSmallScreen = useMediaQuery({ maxWidth: 768 });const isMediumScreen = useMediaQuery({ minWidth: 769, maxWidth: 1024 });const isLargeScreen = useMediaQuery({ minWidth: 1025 });return (<div className={`${styles.container} ${isSmallScreen ? styles.smallScreen : ''} ${isMediumScreen ? styles.mediumScreen : ''} ${isLargeScreen ? styles.largeScreen : ''}`}><p>Content goes here</p></div>);
};export default MyComponent;

4、Harmony中的媒体查询

鸿蒙中主要通过 @ohos.mediaquery 实现媒体查询,进行断点  

// 参考:https://developer.harmonyos.com/cn/docs/documentation/doc-references-V3/js-apis-mediaquery-0000001478181613-V3#ZH-CN_TOPIC_0000001573928789__mediaquerymatchmediasyncimport mediaquery from '@ohos.mediaquery'

4.1 封装媒体查询方法(.ts)

import mediaQuery from '@ohos.mediaquery'class BreakpointSystem {private currentBreakpoint: string = 'md'private smListener: mediaQuery.MediaQueryListenerprivate mdListener: mediaQuery.MediaQueryListenerprivate lgListener: mediaQuery.MediaQueryListenerprivate updateCurrentBreakpoint(breakpoint: string) {if (this.currentBreakpoint !== breakpoint) {this.currentBreakpoint = breakpointAppStorage.Set<string>('currentBreakpoint', this.currentBreakpoint)}console.log('======currentBreakpoint======', this.currentBreakpoint)}private isBreakpointSM = (mediaQueryResult) => {if (mediaQueryResult.matches) {this.updateCurrentBreakpoint('sm')}}private isBreakpointMD = (mediaQueryResult) => {if (mediaQueryResult.matches) {this.updateCurrentBreakpoint('md')}}private isBreakpointLG = (mediaQueryResult) => {if (mediaQueryResult.matches) {this.updateCurrentBreakpoint('lg')}}public register() {this.smListener = mediaQuery.matchMediaSync('(320vp<=width<600vp)')this.smListener.on('change', this.isBreakpointSM)this.mdListener = mediaQuery.matchMediaSync('(600vp<=width<840vp)')this.mdListener.on('change', this.isBreakpointMD)this.lgListener = mediaQuery.matchMediaSync('(840vp<=width)')this.lgListener.on('change', this.isBreakpointLG)}public unregister() {this.smListener.off('change', this.isBreakpointSM)this.mdListener.off('change', this.isBreakpointMD)this.lgListener.off('change', this.isBreakpointLG)}
}export default new BreakpointSystem()

4.2 使用封装的函数

4.2.1 轮播图中使用

import breakpointSystem from '../common/BreakpointSystem'@Component
export default struct IndexSwiper {@StorageProp('currentBreakpoint') currentBreakpoint: string = 'md'@Builder swiperItem(imageSrc) {Image(imageSrc).width('100%').aspectRatio(2.5).objectFit(ImageFit.Fill)}aboutToAppear() {breakpointSystem.register()}aboutToDisappear() {breakpointSystem.unregister()}build() {Swiper() {this.swiperItem($r('app.media.ic_public_swiper1'))this.swiperItem($r('app.media.ic_public_swiper2'))this.swiperItem($r('app.media.ic_public_swiper3'))this.swiperItem($r('app.media.ic_public_swiper1'))this.swiperItem($r('app.media.ic_public_swiper2'))this.swiperItem($r('app.media.ic_public_swiper3'))}.autoPlay(true).indicator(false).itemSpace(10).displayCount(this.currentBreakpoint === 'sm' ? 1 : (this.currentBreakpoint === 'md' ? 2 : 3)).width('100%').padding({ left: 12, right: 12, bottom: 16, top: 16 })}
}

4.2.2 TarBar中使用

import breakpointSystem from '../common/BreakpointSystem'@Entry
@Component
struct Index {@State currentIndex: number = 0@StorageProp('currentBreakpoint') currentBreakpoint: string = 'md'private onTabChange = (index: number) => {this.currentIndex = index}aboutToAppear() {breakpointSystem.register()}aboutToDisappear() {breakpointSystem.unregister()}@BuildertabItem(index: number, title: Resource, icon: Resource, iconSelected: Resource) {TabBarItem({index: index,currentIndex: this.currentIndex,title: title,icon: icon,iconSelected: iconSelected})}build() {Tabs({ barPosition: this.currentBreakpoint === 'lg' ? BarPosition.Start : BarPosition.End }) {TabContent() {Home()}.tabBar(this.tabItem(0, $r('app.string.tabBar1'), $r('app.media.ic_home_normal'), $r('app.media.ic_home_actived')))TabContent() {}.tabBar(this.tabItem(1, $r('app.string.tabBar2'), $r('app.media.ic_app_normal'), $r('app.media.ic_app_actived')))TabContent() {}.tabBar(this.tabItem(2, $r('app.string.tabBar3'), $r('app.media.ic_game_normal'), $r('app.media.ic_mine_actived')))TabContent() {}.tabBar(this.tabItem(3, $r('app.string.tabBar4'), $r('app.media.ic_search_normal'), $r('app.media.ic_search_actived')))}.barWidth(this.currentBreakpoint === 'lg' ? 96 : '100%').barHeight(this.currentBreakpoint === 'lg' ? '60%' : 56).vertical(this.currentBreakpoint === 'lg').onChange(this.onTabChange).backgroundColor('#F1F3F5')}
}

4.3 效果图

5、额外加一个Hilog的封装扩展(.ts)

import hilog from '@ohos.hilog';export class Logger {// 日志对应的领域标识private domain: number = 0xF811;// tag日志标识private prefix: string = '[Logger_Utils]';// 格式字符串,用于日志的格式化输出private format: string = '%{public}s, %{public}s';constructor(prefix: string) {this.prefix = prefix;}debug(...args: string[]): void {hilog.debug(this.domain, this.prefix, this.format, args);}info(...args: string[]): void {hilog.info(this.domain, this.prefix, this.format, args);}warn(...args: string[]): void {hilog.warn(this.domain, this.prefix, this.format, args);}error(...args: string[]): void {hilog.error(this.domain, this.prefix, this.format, args);}
}export default new Logger('[Logger_Utils]');

相关文章:

  • 案例086:基于微信小程序的影院选座系统
  • TCP/IP的网络层(即IP层)之IP地址和网络掩码,在视频监控系统中的配置和应用
  • 简单工厂,工厂方法,抽象工厂模式
  • 原码、反码、补码,计算机中负数的表示
  • 八大算法排序@希尔排序(C语言版本)
  • 【MySQL】数据库之主从复制和读写分离
  • Ubuntu 常用命令之 locate 命令用法介绍
  • 2022年全球运维大会(GOPS深圳站)-核心PPT资料下载
  • LeetCode 2807. 在链表中插入最大公约数
  • HLS 2017.4 导出 RTL 报错:ERROR: [IMPL 213-28] Failed to generate IP.
  • C语言—第1次作业:编译与连接基础知识
  • AI:106-基于卷积神经网络的遥感图像地物分类
  • 2023-12-25 LeetCode每日一题(不浪费原料的汉堡制作方案)
  • k8s的声明式资源管理
  • java struts2教务管理系统Myeclipse开发mysql数据库struts2结构java编程计算机网页项目
  • CNN 在图像分割中的简史:从 R-CNN 到 Mask R-CNN
  • go语言学习初探(一)
  • HomeBrew常规使用教程
  • HTTP中的ETag在移动客户端的应用
  • Java Agent 学习笔记
  • PyCharm搭建GO开发环境(GO语言学习第1课)
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 翻译:Hystrix - How To Use
  • 工作手记之html2canvas使用概述
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 基于遗传算法的优化问题求解
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 前端性能优化——回流与重绘
  • 如何设计一个比特币钱包服务
  • 数组的操作
  • 微信开放平台全网发布【失败】的几点排查方法
  • 用 Swift 编写面向协议的视图
  • 原生 js 实现移动端 Touch 滑动反弹
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • Java总结 - String - 这篇请使劲喷我
  • #pragam once 和 #ifndef 预编译头
  • #传输# #传输数据判断#
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (52)只出现一次的数字III
  • (八)Flask之app.route装饰器函数的参数
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (六)Hibernate的二级缓存
  • (十一)手动添加用户和文件的特殊权限
  • (顺序)容器的好伴侣 --- 容器适配器
  • (图)IntelliTrace Tools 跟踪云端程序
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (总结)Linux下的暴力密码在线破解工具Hydra详解
  • ****** 二十三 ******、软设笔记【数据库】-数据操作-常用关系操作、关系运算
  • *Django中的Ajax 纯js的书写样式1
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .Net 高效开发之不可错过的实用工具
  • .Net各种迷惑命名解释