Closed neo773 closed 2 years ago
Why not do something like this?
const breakpoints = {
320: {
slidesPerView: 1,
spaceBetween: 20,
},
480: {
slidesPerView: 1,
spaceBetween: 30,
},
1112: {
slidesPerView: 3,
spaceBetween: 30,
},
1536: {
slidesPerView: 3,
spaceBetween: 0,
}
}
const swiper = new Swiper('.swiper-container');
const swiperResize = () => {
for (const [breakpoint, options] of Object.entries(breakpoints)) {
if (swiper.env.element.$el.offsetWidth <= +breakpoint) {
swiper.options = Object.assign(swiper.options, options)
break
}
}
swiper.updateSize()
}
const swiperResizeListener = _.debounce(swiperResize, 200)
window.addEventListener('resize', swiperResizeListener, { passive: true })
swiper.on('after-destroy', () => window.removeEventListener('resize', swiperResizeListener))
swiperResize()
@joe223
What about creating an official plugin for breakpoints?
I started a basic implementation which includes a built-in rAF debounce: https://gist.github.com/pryley/3bc6d2f01aa5b68f829a5fbeb19abbd8
A few caveats:
instance.env.element.$el.offsetWidth
to instance.env.measure.viewSize
){ passive: true }
supportHere is a demo: https://tiny-swiper2-demo-plugin-breakpoints.stackblitz.io
@pryley That's really great!Would you like to create a PR :) ?
Here are some questions I considered about
env.measure
instead of element
, avoid accessing real DOM data in state
Layer. That's means you are exactly right, instance.env.measure.viewSize
would be better!{ passive: true }
is not supportedBtw, would it be better if we provide throttle
and debounce
as common utils?
@joe223
instance.env.measure.viewSize
was because that value can represent either the width or height depending on the direction of the swiper.Regarding throttle and debounce, it could be useful to provide these as utils if they are only imported as needed. The debounce implementation was taken from the lodash function and stripped down as much as possible.
@pryley So, the breakpoints
is only for horizontal direction right? 🤔
Yes. The resize event is triggered by the window, but the breakpoint size is defined by the swiper width, not the window size.
How would you suggest this otherwise?
@pryley How about adding a new property of measure
which means the another dimension of view size and cross with slide direction?
I'm not sure height breakpoints would be useful. I think you would be more likely to use a breakpoints feature to change the direction of a swiper rather than to determine if a breakpoint is triggered by vertical or horizontal resizing. The reason measuring by width is more practical is because most devices whhich allow you to resize a browser window (i.e. desktop browsers) have landscape screens.
What if we simply mirrored the breakpoint functionality of swiperjs? It provides two options:
breakpoints
: params objectbreakpointsBase
: string ("window" or "container")Swiperjs only measures width on resize, not height (unless using ratios). The breakpoint keys can be either integer units (as pixel values) or ratio strings (i.e. "@0.75"), however I think to keep it minimal only integer units are really necessary.
https://swiperjs.com/swiper-api#param-breakpoints
I have extracted the debounce functionality into it's own utility function here: https://gist.github.com/pryley/c822c23ec542b6d7b6196de4707c3bdf
So using the Debounce utility function and adding a breakpointsBase
option it would look probably something like this (untested):
import { Debounce } from '../core/render/timing'
import { Options } from '../core/options'
import { SwiperInstance, SwiperPlugin } from '../core/index'
export type SwiperPluginBreakpointsInstance = {}
export type SwiperPluginBreakpointsOptions = {}
/**
* TinySwiper plugin for breakpoints.
*
* @param {SwiperInstance} instance
* @param {Options}
*/
export default <SwiperPlugin>function SwiperPluginBreakpoints (
instance: SwiperInstance & {
breakpoints?: SwiperPluginBreakpointsInstance
},
options: Options & {
breakpoints?: SwiperPluginBreakpointsOptions,
breakpointsBase?: string,
},
): void {
const isEnabled = Boolean(options.breakpoints)
const breakpoints: SwiperPluginBreakpointsInstance = {
update (): void {
for (const [breakpoint, values] of Object.entries(options.breakpoints)) {
if ('window' === options.breakpointsBase) {
if (window.matchMedia(`(min-width: ${breakpoint}px)`).matches) {
instance.options = Object.assign(instance.options, values)
}
} else if (+breakpoint <= instance.env.element.$el.offsetWidth) {
instance.options = Object.assign(instance.options, values)
}
}
instance.updateSize()
},
}
if (!isEnabled) return
const resizeListener = () => Debounce(breakpoints.update)() // the default timeout is 200ms
instance.on('after-init', () => {
window.addEventListener('resize', resizeListener, { passive: true })
requestAnimationFrame(breakpoints.update)
})
instance.on('before-destroy', () => {
window.removeEventListener('resize', resizeListener)
})
}
I think it may be overkill to provide a debounce timeout option, might be better to just provide a sane default. It would be preferable to use ResizeObserver
instead of debounce, but this has reduced browser support.
I won't submit a pull request as I am not familiar enough with Typescript; you would need to perform the actual implementation.
@pryley Great, I'll get this done in Oct
@joe223 Any updates on this?
Hi @pryley @joshauh46 , sorry for the late reply. 2.2.0
was released. API: https://tiny-swiper.js.org/docs/api#breakpoints. Demo: https://tiny-swiper.js.org/docs/demo#breakpoints
Hi there, I was looking through the Documentation and couldn't find a breakpoint parameter that Swiper offers. The library is literally unusable on mobile without this parameter.
breakpoints: { 320: { slidesPerView: 1, spaceBetween: 20 }, 480: { slidesPerView: 1, spaceBetween: 30 }, 1112: { slidesPerView: 3, spaceBetween: 30 }, 1536: { slidesPerView: 3, spaceBetween: 0 } }