使用ResizeObserver制作响应式Vue组件

每个项目产品都会让你加埋点,你是愿意花几天一个个加,还是愿意几分钟一个小时加完去喝茶聊天?来试试这520web工具, 高效加埋点,目前我们公司100号前端都在用,因为很好用,所以很自然普及开来了,推荐给大家吧

http://www.520webtool.com/

自己开发所以免费,埋点越多越能节约时间,点两下埋点就加上了,还不会犯错,里面有使用视频,反正免费 😄

使用ResizeObserver制作响应式Vue组件

前言

  • 一提到制作响应式组件或布局,脑海里首先想到的是通过@media查询来控制,但是有一个问题,它能满足你的需求么?大多数情况下可以很好的解决问题,有时也会不灵验。已一个例子作为说明。
  • 假设你要创建一个postItem组件,在大屏上post是这样的显示效果
  • image
  • 在手机上我需要这样的效果
  • image
  • 第一反应就是想到媒体查询,根据页面的宽度来控制样式,于是就有了下面的样式。
@media only screen and (max-width: 576px) {
  .post__item {
    flex-direction: column;
  }
  
  .post__image {
    flex: 0 auto;
    height: auto;
  }
}
复制代码
  • 组件具有重用性,不是一次买卖,某天需求变了要在一个页面上根据post的类别来显示,效果如下
  • image
  • @media查询的最大问题是,组件响应性基于屏幕大小,但应基于其自身大小,这时原来的媒体查询就不灵验了。在这种情况下,组件布局仅取决于它们。这些组件应该是原子的,独立地确定它们自己的大小并使其适应布局。构建响应式组件,ResizeObserver是个不错的选则。

介绍ResizeObserver

  • ResizeObserver:是一项新的功能,监听元素的内容矩形大小的变更,并通知做出相应的反应。和document.onresize的功能很相似。
const observer = new ResizeObserver(entries => {
  entries.forEach(entry => {
    const cr = entry.contentRect;
    console.log('Element:', entry.target);
    console.log(`Element size: ${cr.width}px x ${cr.height}px`);
    console.log(`Element padding: ${cr.top}px ; ${cr.left}px`);
  })
})

observer.observe(someElement)
复制代码
  • 浏览器的支持性,如图所示
  • image
  • 虽然目前主流浏览器对ResizeObserver不支持,庆幸的是,ResizeObserver有基于MutationObserver的polyfill,而主流浏览器对MutationObserv是支持的
  • image

使用

  • 作为组件
<template>
  <Responsive :breakpoints="{
    small: el => el.width <= 500
  }">
    <div slot-scope="el" :class="['post__item', { small: el.is.small }]">
      <img class="post__image" :src="post.image" />
      <div class="post__text">{{post.text}}</div>
    </div>
  </Responsive>
</template>

<script>
import { Responsive } from "vue-responsive-components"
export default {
  props: ['post'],
  components: { Responsive }
}
</script>

<style lang="scss">
.post__item {
  display: flex;
}
.post__image {
  flex: 0 0 200px;
  height: 200px;
}
.post__item.small {
  flex-direction: column;
  
  .post__image {
    flex: 0 auto;
    height: auto;
  }
}
</style>
复制代码
  • 作为指令
<template>
  <!-- Will add/remove .small if the width is less / greater -->
  <div class="post__item" v-responsive="{ small: el => el.width <= 500 }">
    <img class="post__image" :src="post.image" />
    <div class="post__text">{{post.text}}</div>
  </div>
</template>

<script>
import { ResponsiveDirective } from "vue-responsive-components"
export default {
  props: ["post"],
  directives: {
    responsive: ResponsiveDirective
  }
}
</script>
复制代码

插件代码实现

  • npm install resize-observer-polyfill --save-dev
  • npm install loadsh --save-dev
import throttle from "lodash.throttle"
import ResizeObserver from "resize-observer-polyfill"

export const ResponsiveMixin = {
  data() {
    return {
      el: {
        width: 0,
        height: 0,
        is: {}
      }
    }
  },
  mounted() {
    if (
      typeof process === "undefined" ||
      (!process.server && (this.breakpoints || this.$options.breakpoints))
    ) {
      this.$nextTick(() => {
        const handleResize = throttle(entries => {
          const cr = entries[0].contentRect
          ;(this.el.width = cr.width), (this.el.height = cr.height)
          const conds = Object.assign(
            {},
            this.breakpoints || {},
            this.$options.breakpoints || {}
          )
          for (const breakpoint in conds) {
            this.$set(this.el.is, breakpoint, conds[breakpoint](this.el))
          }
        }, 200)

        const observer = new ResizeObserver(handleResize)
        if (this.$el instanceof Element) {
          observer.observe(this.$el)
        }
      })
    }
  }
}

export const Responsive = {
  data() {
    return { init: false }
  },
  props: {
    noHide: { type: Boolean, default: false },
    breakpoints: { type: Object, default: undefined }
  },
  mixins: [ResponsiveMixin],
  render(h) {
    const slot =
      (this.$scopedSlots.default && this.$scopedSlots.default(this.el)) ||
      this.$slots.default

    return !this.noHide && !this.init
      ? h(
          "div",
          {
            style: { visibility: "hidden" }
          },
          [slot]
        )
      : slot
  },
  mounted() {
    this.init = true
  }
}

export const ResponsiveDirective = {
  inserted(el, conds) {
    if (typeof process === "undefined" || !process.server) {
      const handleResize = throttle(entries => {
        const cr = entries[0].contentRect
        for (const breakpoint in conds.value) {
          if (conds.value[breakpoint](cr)) {
            el.classList.add(breakpoint)
          } else {
            el.classList.remove(breakpoint)
          }
        }
      }, 200)

      const observer = new ResizeObserver(handleResize)
      observer.observe(el)
    }
  }
}

export const VueResponsiveComponents = Vue => {
  Vue.component("Responsive", Responsive)
  Vue.directive("responsive", ResponsiveDirective)
}
复制代码

总结

  • ResizeObserver对响应式布局提供了一种新颖的解决思路,让组件保持了原子性、独立性,同样的思路也适用于angular、react等组件写法(注意需根据angular、react语法规则更改)。

 


作者:chen小白
链接:https://juejin.im/post/5b4f0c56e51d4518ef2cda0f
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用resizeobserver可以制作响应式Vue组件。ResizeObserver是一个浏览器API,用于监测DOM元素的尺寸变化。在Vue中,我们可以通过监听ResizeObserver API来实现组件响应式。 首先,我们需要在Vue组件中引入ResizeObserver。可以通过npm安装resize-observer-polyfill库,该库提供了ResizeObserver的Polyfill兼容方案,以便在不支持ResizeObserver的浏览器上使用。 安装完成后,我们可以在Vue组件的mounted生命周期钩子中创建ResizeObserver实例,并监听需要响应式的DOM元素。例如: ```javascript import ResizeObserver from 'resize-observer-polyfill'; export default { mounted() { const resizeObserver = new ResizeObserver(entries => { // 处理尺寸变化的逻辑,可以在这里更新组件的状态或执行相应操作 }); const targetElement = this.$refs.targetElement; // 获取需要监听尺寸变化的DOM元素 resizeObserver.observe(targetElement); // 监听DOM元素的尺寸变化 } } ``` 在上述例子中,我们创建了一个ResizeObserver实例,并指定了一个回调函数来处理尺寸变化的逻辑。然后,通过$refs来获取需要监听尺寸变化的DOM元素,并调用resizeObserver的observe方法来开始监听。 在回调函数中,我们可以根据尺寸变化来更新组件的状态或执行其他相应的操作,以达到实现响应式的效果。 需要注意的是,当组件销毁时,我们需要手动调用resizeObserver的unobserve方法来停止监听,以避免内存泄漏。例如,在Vue组件的beforeDestroy生命周期钩子中: ```javascript beforeDestroy() { const targetElement = this.$refs.targetElement; resizeObserver.unobserve(targetElement); } ``` 通过使用resizeobserver制作响应式Vue组件,可以很方便地实现针对DOM元素尺寸变化的自适应响应。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值