Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

MatchMedia component library for Vue

License

NotificationsYou must be signed in to change notification settings

CyberAP/vue-component-media-queries

Repository files navigation

npmBundle size

Media Queries component library for Vue.

Key features:

  • 🍳Lightweight. Less than 1kb gzippedtotal size.
  • 🤗User-friendly. Does not require global installation, can beused on a per-component level.
  • 💊Versatile. Works both on a component level (inside<template>) or as aninjected property (inside<script>).
  • 💡Server Rendered. Zero hydration errors, compatible with Nuxt.js or custom SSR, supportspredictive rendering.
  • 🌳Tree-shakeable. Import only the necessary components right where you need them.
  • 🧹Clean. Does not pollute your component's context.

Live playground on codesandbox

Define your responsive breakpoints via media queries and place them right in your components:

<!-- App.vue --><template><MediaQueryProvider:queries="{ mobile: '(max-width: 680px)' }"><AppLayout/></MediaQueryProvider></template>
<!-- AppLayout.vue --><template><MatchMediav-slot="{ mobile }"><MobileLayoutv-if="mobile"/><DesktopLayoutv-else/></MatchMedia></template>

Before you start

There are two ways how you can use Media Queries on Web: CSS and JS runtime.In most cases you'll be fine with just CSS, so before going any further please verify that CSS is insufficient for your case.For example, you don't need this library if you need to toggle element visibility for non-complex elements.You're better off using just CSS for that:

<divclass="show-on-desktop">You're on mobile</div><divclass="show-on-mobile">You're on desktop</div>
@media (min-width:761px) {  .show-on-mobile {display: none!important; }}@media (max-width:760px) {  .show-on-desktop {display: none!important; }}

But if you encounter a significant performance degradation from rendering everything in a single passor have some logic bound to media queries you might want to usewindow.matchMedia.This library provideswindow.matchMedia integration for Vue.

Table of contents

Getting started

Installation

NPM

  1. Install library as a dependency:npm i vue-component-media-queries

  2. Import components via named exports where necessary:

    import{MediaQueryProvider,MatchMedia}from'vue-component-media-queries'

CDN

If you don't have an option to use NPM you can use a CDN package,it will register a globalVueComponentMediaQueries variable with appropriate exports.The CDN method is not recommended for production usage. Prefer using NPM method whenever possible.

  1. Import library after Vue:

    <scriptsrc="https://unpkg.com/vue@2.6.11/dist/vue.js"></script><scriptsrc="https://unpkg.com/vue-component-media-queries@1.0.0/dist/index.js"></script>
  2. Get components from the globalVueComponentMediaQueries object:

    <script>const{ MatchMedia, MediaQueryProvider}=VueComponentMediaQueries;// ...</script>

Usage

Global matching

If you have an app with lots of components that depend on media queries your best option is to useGlobal matching method.

There are two components required for this method:<MediaQueryProvider> and<MatchMedia>.

  1. <MediaQueryProvider> does the actual matching and provides values down the render tree. You should wrap your whole app with this component in yourApp.vue orLayout.vue.
  2. <MatchMedia> retrieves these values from the<MediaQueryProvider> and exposes them to rendering context through scoped slots.You should put this component where you have to actually use these media queries.

Here's a basic setup for this method:

  1. Wrap your app in a<MediaQueryProvider> and passqueries object to it.

    <template><MediaQueryProvider:queries="$options.queries"><AppLayout/></MediaQueryProvider></template><script>import{MediaQueryProvider}from"vue-component-media-queries";importAppLayoutfrom"./AppLayout.vue";constqueries={mobile:'(max-width: 760px)'};exportdefault{name:'App',    queries,components:{      MediaQueryProvider,      AppLayout,},}</script>
  2. In any part of your app that's within the<MediaQueryProvider> use<MatchMedia> component to retrieve the results of media queries.

    <template><MatchMediav-slot="{ mobile }"><MobileLayoutv-if="mobile"/><DesktopLayoutv-else/></MatchMedia></template><script>import{MatchMedia}from"vue-component-media-queries";importMobileLayoutfrom"./MobileLayout.vue";importDesktopLayoutfrom"./DesktopLayout.vue";exportdefault{name:'AppLayout',components:{      MatchMedia,      MobileLayout,      DesktopLayout,},}</script>

<MatchMedia v-slot="{ mobile }"> in the example above refers to themobile: '(max-width: 760px)' media query result taken from the<MediaQueryProvider>.This result is reactive – when you resize the page it will update accordingly.


Component-based

<MatchMedia> can be used without<MediaQueryProvider>.This is convenient if you have just a few components that need media queries.In that case you'll have to pass aquery directly to<MatchMedia> and get the result from amatches slot prop.

<template><MatchMediaquery="(max-width: 760px)"v-slot="{ matches }"><MobileLayoutv-if="matches"/><DesktopLayoutv-else/></MatchMedia></template><script>import{MatchMedia}from"vue-component-media-queries";importMobileLayoutfrom"./MobileLayout.vue";importDesktopLayoutfrom"./DesktopLayout.vue";exportdefault{name:'AppLayout',components:{      MatchMedia,      MobileLayout,      DesktopLayout,},}</script>

If you have a lot of these components you might prefer usingGlobal matching method instead.


Global matching with Provide\Inject

It's possible to have just<MediaQueryProvider> and no<MatchMedia> components.This is needed when you want to use your media queries insidecomputed orwatch.Provide\Inject pattern can be used to get media queries results.

To get the provided media queries results you'll need to:

  1. Set up<MediaQueryProvider> as shown inGlobal matching method.

  2. InjectmediaQueries in your component:

    <template><divv-text="title"/></template><script>exportdefault{name:'ResponsiveComponent',inject:['mediaQueries'],computed:{title(){returnthis.mediaQueries.mobile ?`You're on a mobile layout` :`You're on a desktop layout`;}}}</script>

API

<MediaQueryProvider>

Props

queries

Type:{ [name]: string }

Required:yes

queries is an object where:

  • name is a media query name that would be then used in<MatchMedia> scoped slot (<MatchMedia v-slot="{ name }">) or inmediaQueries injection (this.mediaQueries.name).
  • string value is amedia query.It is handled internally with thewindow.matchMedia API.
constqueries={mobile:'(max-width: 760px)',tablet:'(max-width: 1024px)',desktop:'(min-width: 1024px)',landscape:'(orientation: landscape)'}

queries are best passed to<MediaQueryProvider> via the$options objectbecause$options contents are static and so should be your media queries object.

<template><MediaQueryProvider:queries="$options.queries"><AppLayout/></MediaQueryProvider></template><script>import{MediaQueryProvider}from'vue-component-media-queries';importAppLayoutfrom'./AppLayout.vue';constqueries={mobile:'(max-width: 760px)',tablet:'(max-width: 1024px)',desktop:'(min-width: 1024px)',landscape:'(orientation: landscape)'};exportdefault{name:'App',components:{    MediaQueryProviderAppLayout,},  queries,// queries can now be used as part of an $options object}</script>
fallback

Type:string orstring[]

A key or a list ofqueries keys that should returntrue whenwindow.matchMedia is unavailable (node.js\nuxt.js for example).

<MediaQueryProvider:queries="{ mobile: '(max-width: 760px)' }"fallback="mobile"><MatchMediav-slot="{ mobile }">    {{ mobile }}<!-- will be true on server, will automatically update on client --></MatchMedia></MediaQueryProvider>

Multiple fallbacks:

<MediaQueryProvider:queries="{ mobile: '(max-width: 760px)', landscape: 'orientation: landscape' }":fallback="['mobile', 'landscape']"></MediaQueryProvider>
ssr

Type:boolean

This prop switches between eager and lazy mode for matching to avoid hydration mismatch errors.

  • false – Eager mode sets all the queries to match before your components render.It ensures that components using media queries won't have to re-render after a first render due to data mismatch(all media queries returnfalse before matching, except those listed infallback prop).
  • true – Lazy mode allows for components to render with fallback values first (passed tofallback prop) to avoid hydration errors.
<MediaQueryProvider:queries="{ mobile: '(max-width: 760px)', landscape: 'orientation: landscape' }":fallback="['mobile', 'landscape']"ssr></MediaQueryProvider>

Set this prop totrue if you have a custom server side rendering.Nuxt.js users will have this set totrue by default.

wrapperTag

Type:string

Default:span

A wrapping tag that is used when a component has more than one child.

<MediaQueryProvider:queries="$options.queries"wrapper-tag="div"><FirstChild/><SecondChild/></MediaQueryProvider>

Events

change:[name]

Type:MediaQueryListEvent

Arguments:

  • matches – boolean. Represents media query result.
  • media — string. Media query.
  • Rest ofEventTarget interface.

An even fired when a media queryname result changes.name is a key ofqueries object passed to<MediaQueryProvider>.

<template><MediaQueryProvider@change:mobile="onMobileChange":queries="$options.queries"><AppLayout/></MediaQueryProvider></template><script>import{MediaQueryProvider}from'vue-component-media-queries';importAppLayoutfrom'./AppLayout.vue';constqueries={mobile:'(max-width: 760px)'};exportdefault{name:'App',components:{    MediaQueryProviderAppLayout,},  queries,methods:{onMobileChange(event){const{ matches, media, ...rest}=event;// some logic},},}</script>

<MatchMedia>

Props

query

Type:string, amedia query.

Required: yes, when is not a descendant of<MediaQueryProvider>.

A media query that needs to be matched in place. Seeusage section for an example.

fallback

Type:string

Setsmatches value totrue when used outside of browser context (same as for<MediaQueryProvider>).

<MatchMediaquery="(max-width: 760px)":fallback="isServer"v-slot="{ matches }">  {{ matches }}<!-- will be `true` on server --></MatchMedia>
ssr

Type:boolean

Same as for<MediaQueryProvider>.

wrapperTag

Type:string

Default:span

A wrapping tag that is used when a component has more than one child.

<MatchMediav-slot="{ mobile }"><FirstChildv-if="mobile"/><SecondChild/></MatchMedia>

Scoped Slots

default slot

Slot props:{ [name]: boolean } or{ matches: boolean }

Returns a record of media queries results from the<MediaQueryProvider>.

<MatchMediav-slot="{ mobile }">{{ mobile }}<!-- a result of `mobile` media query from <MediaQueryProvider> --></MatchMedia>

Or returns amatches slot prop if you pass aquery prop.

<MatchMediaquery="(max-width: 760px)"v-slot="{ matches }">{{ matches }}<!-- doesn't need <MediaQueryProvider> --></MatchMedia>

Events

change

Type:MediaQueryListEvent

Arguments:

  • matches – boolean. Represents media query result.
  • media — string. Media query.
  • Rest ofEventTarget interface.

Triggers when a result from passed mediaquery prop changes.

<MatchMediaquery="(max-width: 760px)"@change="onMedia"/>

mediaQueries injection

Type:{ [name]: boolean }

A record with the results of<MediaQueryProvider>. SeeProvide\Inject section for an example.

SSR

Predictive rendering

You can use user agent detection (also called browser sniffing) to make a guess which media queries should be matched on server.This is useful when you want to avoidlayout shifts and unnecessary re-renders after a hydration.

To do so, we'll have to parse user agent on server side, set fallback values for<MediaQueryProvider> and pass them back to the client.

Here's an example of usingua-parser-js to make a guess which device is sending a request in a default Nuxt.js layout:

<template><MediaQueryProvider:queries="$options.queries":fallback="fallback"><Nuxt/></MediaQueryProvider></template><script>import{MediaQueryProvider}from'vue-component-media-queries';exportdefault{name:'DefaultLayout',queries:{mobile:'(max-width: 760px)'},components:{      MediaQueryProvider},asyncfetch(){if(this.$nuxt.context.req){// ua-parser-js is dynamically imported to avoid including it in the client bundleconst{default:uaparser}=awaitimport('ua-parser-js');const{ device}=uaparser(this.$nuxt.context.req.headers['user-agent']);if(device.type==='mobile'){this.fallback='mobile';}}},data(){return{fallback:null};},}</script>

About

MatchMedia component library for Vue

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors2

  •  
  •  

[8]ページ先頭

©2009-2025 Movatter.jp