vue-ssr-carousel
Version:
A performance focused Vue carousel designed for SSR/SSG environments.
124 lines (101 loc) • 4.58 kB
text/coffeescript
###
Code related to measuring the size of the carousel after mounting
###
export default
data: ->
viewportWidth: null # Width of the viewport, for media query calculation
carouselWidth: null # Width of a page of the carousel
gutterWidth: 0 # Computed width of gutters, since they support css vars
# Add resize listening
mounted: ->
@onResize()
# Resize observer listens for the element itself to change dimensions
if @$el?.nodeType == Node.ELEMENT_NODE
@resizeObserver = new ResizeObserver @onResize
@resizeObserver.observe @$el
beforeDestroy: ->
@resizeObserver?.disconnect()
computed:
# The width of a page of slides, which may be less than the carouselWidth
# if there is peeking. This includes the affect of gutters.
pageWidth: -> @carouselWidth - @combinedPeek
# Calculate the width of a slide based on client side measured pageWidth
# rather than measuring it explicitly in the DOM. This value includes the
# gutter.
slideWidth: -> @pageWidth / @currentSlidesPerPage
# Calculate the width of the whole track from the slideWidth.
trackWidth: ->
if @isVariableWidth
then @measuredTrackWidth + @gutterWidth
else @slideWidth * @slidesCount
# Figure out the width of the last page, which may not have enough slides
# to fill it.
lastPageWidth: ->
# Determine how many slides are on the final page of pagination. If the
# remainder was 0, that means the page is flush with slides, so swap
# the 0 for the max amount.
slidesPerPage = @currentSlidesPerPage
slidesOnLastPage = @slidesCount % slidesPerPage
if slidesOnLastPage == 0
then slidesOnLastPage = slidesPerPage
# Turn the slide count into a width value
width = slidesOnLastPage * @slideWidth
return width
# The ending x value, only used when not looping. The peeking values in
# here result in the final page using the left peeking value and the
# actualy peeking appearing to apply to the left. The +1 is to fix subpixel
# rounding issues.
endX: ->
if @disabled then 0
else @pageWidth - @trackWidth - @peekLeftPx + @peekRightPx + 1
# Check if the drag is currently out bounds
isOutOfBounds: -> @currentX > 0 or @currentX < @endX
# Helper for things that are triggered once dimensions are known so
# they can be more specific about their dependencies
dimensionsKnown: -> @carouselWidth and @viewportWidth
methods:
# Measure the component width for various calculations. Using
# getBoundingClientRect so we can get fractional values. We also need
# the width of the gutter since that's effectively part of the page.
onResize: ->
return unless @$el?.nodeType == Node.ELEMENT_NODE
return unless firstSlide = @$refs.track.$el.firstElementChild
@gutterWidth = parseInt getComputedStyle(firstSlide).marginRight
@carouselWidth = @$el.getBoundingClientRect().width + @gutterWidth
@viewportWidth = window.innerWidth
@capturePeekingMeasurements()
@captureCarouselDims() if @isVariableWidth
# Make the width style that gives a slide it's width given
# slidesPerPage. Reduce this width by the gutter if present
makeBreakpointSlideWidthStyle: (breakpoint) ->
return if @isVariableWidth
"""
#{@scopeSelector} .ssr-carousel-slide {
width: #{@makeSlideWidthCalc(breakpoint)};
}
"""
# Build the calc string which makes a percentage width for a slide and
# reduces it by combined peeking and gutter influence. The computed
# style this produces should have an equal value to the `slideWidth`
# computed property which is client side JS dependent.
makeSlideWidthCalc: (breakpoint) ->
isDisabled = @isDisabledAtBreakpoint breakpoint
slidesPerPage = @getResponsiveValue 'slidesPerPage', breakpoint
gutter = @getResponsiveValue 'gutter', breakpoint
# A common use case when not looping is to have a larger peek on just the
# right. But when disabled, this looks strange. So this balances out
# the peeking in the disbaled state.
peekLeft = @getResponsiveValue 'peekLeft', breakpoint
if @matchPeekWhenDisabled and isDisabled then peekRight = peekLeft
else peekRight = @getResponsiveValue 'peekRight', breakpoint
# Render the styles
"calc(
#{100 / slidesPerPage}% -
(#{@autoUnit(peekLeft)} + #{@autoUnit(peekRight)}) / #{slidesPerPage} -
(#{@autoUnit(gutter)} * #{slidesPerPage - 1}) / #{slidesPerPage}
)"
# Get the target X scroll position of a given slide
targetXOfIdx: (idx) ->
if @isVariableWidth
then @measuredSlidesWidths[idx].targetXScroll
else @pageWidth / @currentSlidesPerPage