Intersection Directive

"Intersection"是使用Intersection Observer API监听当 DOM/组件在可视窗口中出现或者消失(由页面滚动导致)时触发一个函数的 Quasar 指令。

WARNING

并不是所有的浏览器都支持 Intersection Observer API,虽然大部分浏览器都支持,但是如果您需要兼容老的浏览器,那么您需要安装 W3C 官方的polyfill(通过一个 boot 文件引入)。

Intersection API

Intersection API

类型
Object | Function
说明
发生滚动时要调用的函数(与对象形式的 'handler' 属性的描述相同);如果使用对象形式,强烈建议从 vue 组件作用域中引用它,而不是内联定义它,否则指令更新周期将持续重新创建观察者将严重影响性能

用法

请先阅读 Intersection Observer API页面,以便您了解这个指令工作的原理。

Intersection 指令可以接受一个函数或者对象作为其值,对象的格式如下:

{
  handler: /* Function */,
  cfg: {
    // 可选的参数,来自 "Intersection observer options"
    // 参考 https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
    root: null, // DOM Element
    rootMargin: '0px',
    threshold: 0
  }
}

当使用对象格式的值时,其中只有handler时必填的。

这个handler函数有一个参数,参考IntersectionObserverEntry.

TIP

在下面的示例中,请持续滚动页面直到被监测的对象出现/消失

基础



<template>
  <div class="relative-position">
    <div class="example-area q-pa-lg scroll">
      <div class="example-filler" />

      <div v-intersection="onIntersection" class="example-observed text-center rounded-borders">
        Observed Element
      </div>

      <div class="example-filler" />
    </div>

    <div
      class="example-state rounded-borders text-center absolute-top q-mt-md q-ml-md q-mr-lg text-white"
      :class="visibleClass"
    >
      {{ visible === true ? 'Visible' : 'Hidden' }}
    </div>
  </div>
</template>

Observed Element
Hidden

只触发一次

这个指令可以被once修饰符修饰,(示例: v-intersection.once),则 hanler 函数只会被触发一次。如果您所需要的只是在观察到的元素开始出现在屏幕上时得到通知,那么您可以使用这种方式以控制开销。



<template>
  <div class="relative-position">
    <div class="example-area q-pa-lg scroll">
      <div class="example-filler" />

      <div v-intersection.once="onIntersection" class="example-observed text-center rounded-borders">
        Observed Element
      </div>

      <div class="example-filler" />
    </div>

    <div
      class="example-state rounded-borders text-center absolute-top q-mt-md q-ml-md q-mr-lg text-white"
      :class="visibleClass"
    >
      {{ visible === true ? 'Visible' : 'Hidden' }}
    </div>
  </div>
</template>

Observed Element
Hidden

使用对象格式

使用一个对象来作为指令的值,您可以更精确的控制监听的行为。



<template>
  <div class="relative-position">
    <div
      class="example-state rounded-borders text-center absolute-top q-mt-md q-ml-md q-mr-lg text-white"
      :class="visibleClass"
    >
      Percent: {{ percent }}%
    </div>

    <div class="example-area q-pa-lg scroll">
      <div class="example-filler" />

      <div v-intersection="options" class="example-observed flex flex-center rounded-borders">
        Observed Element
      </div>

      <div class="example-filler" />
    </div>
  </div>
</template>

Percent: 0%
Observed Element

进阶

下面是一些更高阶的用法,代码中使用了 HTML 的 data 属性,将元素的索引绑定到data-id上,然后通过 handler 函数的entry参数中的entry.target.dataset.id访问到设置的 id。如果您还不熟悉 HTML 的 data 属性,请参考:here



<template>
  <div class="relative-position">
    <div class="example-area q-pa-lg scroll">
      <div class="example-filler" />

      <q-list>
        <q-item
          v-for="n in 30"
          :key="n"
          :data-id="n"
          class="q-my-md q-pa-sm bg-grey-3"
          v-intersection="onIntersection"
        >
          <q-item-section class="text-center" style="background: #eee">
            Item #{{ n }}
          </q-item-section>
        </q-item>
      </q-list>

      <div class="example-filler" />
    </div>

    <div class="example-state bg-primary text-white overflow-hidden rounded-borders text-center absolute-top-left q-ma-md q-pa-sm">
      <transition-group v-if="inView.length > 0" name="in-view" tag="ul">
        <li v-for="i in inView" :key="i" class="in-view-item">
          {{i}}
        </li>
      </transition-group>
    </div>
  </div>
</template>

Item #1
Item #2
Item #3
Item #4
Item #5
Item #6
Item #7
Item #8
Item #9
Item #10
Item #11
Item #12
Item #13
Item #14
Item #15
Item #16
Item #17
Item #18
Item #19
Item #20
Item #21
Item #22
Item #23
Item #24
Item #25
Item #26
Item #27
Item #28
Item #29
Item #30

下面的示例中,我们有非常多的卡片,但是只有处于可视窗口中的卡片才会被渲染。

下面的示例也可以使用 QIntersection 组件以一种更简单的方式和实现。



<template>
  <div class="q-pa-md">
    <div class="row justify-center q-gutter-sm">
      <div
        v-for="index in inView.length"
        :key="index"
        :data-id="index - 1"
        class="example-item q-pa-sm flex flex-center relative-position"
        v-intersection="onIntersection"
      >
        <transition name="q-transition--scale">
          <q-card v-if="inView[index - 1]">
            <img src="https://cdn.quasar.dev/img/mountains.jpg">

            <q-card-section>
              <div class="text-h6">Card #{{ index }}</div>
              <div class="text-subtitle2">by John Doe</div>
            </q-card-section>
          </q-card>
        </transition>
      </div>
    </div>
  </div>
</template>

TIP

上面的示例使用了 Quasar 的过渡效果,关于更多的过渡动画,请查看Transitions页面。

视频讲解

若仍有疑惑,请观看视频讲解