ソースを参照

feat(sticky): sticky小程序跳动现象修复(#1571)

suzigang 3 年 前
コミット
c35b52fc04

+ 7 - 4
src/packages/__VUE/sticky/doc.en-US.md

@@ -4,6 +4,8 @@
 
 The effect is the same as `position: sticky` in `CSS`, which can be used for compatibility with low-end browsers
 
+> The applet only supports the ceiling effect, you can also use the official recommendation https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/extended/component-plus/sticky.html
+
 ### Install
 
 ```javascript
@@ -129,13 +131,14 @@ app.use(Sticky);
 |--------------|----------------------------------|--------|------------------|
 | position         | Adsorption position(`top`、`bottom`)               | String | `top`                |
 | top         | Ceiling distance               | Number | `0`                |
-| bottom         | Suction distance               | Number | `0`                |
-| container         | The 'HTML' node of the container needs to specify the `id` at the same time in the miniProgram        | Element | -                |
+| bottom`miniprogram not supported, Directly by setting top`         | Suction distance               | Number | `0`                |
+| container`miniprogram not supported`         | The 'HTML' node of the container needs to specify the `id` at the same time in the miniProgram        | Element | -                |
 | z-index         | Level of adsorption               | Number | `2000`               |
+| parent-height`miniprogram added`         | Set sticky element parent height               | Number | `667`               |
 
 ### Events
 
 | Event | Description                  | Arguments   |
 |--------|----------------|--------------|
-| change  | Triggered when the adsorption state changes | `val: Boolean` |
-| scroll  | Triggered when scrolling | `{ top: Number, fixed: Boolean }` |
+| change`miniprogram not supported`  | Triggered when the adsorption state changes | `val: Boolean` |
+| scroll`miniprogram not supported`  | Triggered when scrolling | `{ top: Number, fixed: Boolean }` |

+ 8 - 5
src/packages/__VUE/sticky/doc.md

@@ -2,7 +2,9 @@
 
 ### 介绍
 
-效果同 `css` 中的 `position: sticky`,对低端浏览器可使用其做兼容
+效果同 `css` 中的 `position: sticky`,对低端浏览器可使用其做兼容。
+
+> 小程序只支持吸顶效果,也可以使用官方推荐 https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/extended/component-plus/sticky.html
 
 ### 安装
 
@@ -129,13 +131,14 @@ app.use(Sticky);
 |--------------|----------------------------------|--------|------------------|
 | position         | 吸附位置(`top`、`bottom`)               | String | `top`                |
 | top         | 吸顶距离               | Number | `0`                |
-| bottom         | 吸底距离               | Number | `0`                |
-| container         | 容器的 `HTML` 节点, 在小程序环境下需要同时指定 `id`               | Element | -                |
+| bottom`小程序不支持,直接通过设置top实现`         | 吸底距离               | Number | `0`                |
+| container`小程序不支持`         | 容器的 `HTML` 节点, 在小程序环境下需要同时指定 `id`               | Element | -                |
 | z-index         | 吸附时的层级               | Number | `2000`               |
+| parent-height`小程序新增`         | 设置粘性元素父级高度               | Number | `667`               |
 
 ### Events
 
 | 事件名 | 说明           | 回调参数     |
 |--------|----------------|--------------|
-| change  | 吸附状态改变时触发 | `val: Boolean` |
-| scroll  | 滚动时触发 | `{ top: Number, fixed: Boolean }` |
+| change`小程序不支持`  | 吸附状态改变时触发 | `val: Boolean` |
+| scroll`小程序不支持`  | 滚动时触发 | `{ top: Number, fixed: Boolean }` |

+ 3 - 0
src/packages/__VUE/sticky/index.scss

@@ -1,4 +1,7 @@
 .nut-sticky {
+  &--stickyed {
+    position: sticky;
+  }
   &--fixed {
     position: fixed;
   }

+ 10 - 125
src/packages/__VUE/sticky/index.taro.vue

@@ -1,173 +1,58 @@
 <script lang="ts">
-import { reactive, computed, h, ref, Ref, unref, PropType, watch, CSSProperties } from 'vue';
-import Taro, { usePageScroll, useReady } from '@tarojs/taro';
+import { computed, h, ref, CSSProperties } from 'vue';
 import { createComponent } from '@/packages/utils/create';
-import { useTaroRect } from '@/packages/utils/useTaroRect';
 const { componentName, create } = createComponent('sticky');
 export default create({
   props: {
-    position: {
-      type: String,
-      default: 'top'
-    },
     top: {
       type: [Number, String],
       default: 0
     },
-    bottom: {
-      type: [Number, String],
-      default: 0
-    },
-    container: {
-      type: Object as PropType<Element>
-    },
     zIndex: {
       type: [Number, String],
       default: 2000
+    },
+    parentHeight: {
+      type: [Number],
+      default: 667
     }
   },
   emits: ['change', 'scroll'],
 
   setup(props, { emit, slots }) {
     const root = ref<HTMLElement>();
-    const query = Taro.createSelectorQuery();
-    const refRandomId = Math.random().toString(36).slice(-8);
-    const state = reactive({
-      width: 0,
-      height: 0,
-      fixed: false,
-      transform: 0
-    });
 
     const rootStyle = computed(() => {
-      const { fixed, width, height } = state;
-
-      if (fixed) {
-        return {
-          width: `${width}px`,
-          height: `${height}px`
-        };
-      }
+      return {
+        height: `${props.parentHeight}px`
+      };
     });
 
     const stickyStyle = computed(() => {
-      if (!state.fixed) return;
-
       const style: CSSProperties = {
-        width: `${state.width}px`,
-        height: `${state.height}px`,
-        [props.position]: `${offset.value}px`,
+        top: `${props.top}px`,
         zIndex: +props.zIndex
       };
 
-      if (state.transform) style.transform = `translate3d(0, ${state.transform}px, 0)`;
-
       return style;
     });
 
-    const offset = computed(() => {
-      return props.position === 'top' ? props.top : props.bottom;
-    });
-
-    const isHidden = (elementRef: HTMLElement | Ref<HTMLElement | undefined>) => {
-      const el = unref(elementRef);
-      if (!el) return false;
-      return new Promise((resolve, reject) => {
-        query
-          .select(`#${el.id}`)
-          .fields(
-            {
-              computedStyle: ['display', 'position']
-            },
-            (res) => {
-              const hidden = res.display === 'none';
-              const parentHidden = el.offsetParent === null && res.position !== 'fixed';
-              resolve(hidden || parentHidden);
-            }
-          )
-          .exec();
-      });
-    };
-
-    const isExistRoot = async () => {
-      const hidden = await isHidden(root);
-      if (!root.value || hidden) return false;
-      return true;
-    };
-
     const renderFixed = () => {
       return h(
         'view',
         {
           style: stickyStyle.value,
-          class: state.fixed ? `${componentName} nut-sticky--fixed` : componentName
+          class: `${componentName} nut-sticky--stickyed`
         },
         slots.default?.()
       );
     };
 
-    const onScroll = async (scrollTop: number) => {
-      if (!isExistRoot()) return;
-
-      const { container, position } = props;
-
-      const rootRect = await useTaroRect(root, Taro);
-
-      if (rootRect.width || rootRect.height) {
-        state.width = rootRect.width;
-        state.height = rootRect.height;
-      }
-
-      if (position === 'top') {
-        if (container) {
-          const containerRect = await useTaroRect(container, Taro);
-          const diff = containerRect.bottom - +offset.value - state.height;
-          state.fixed = +offset.value > rootRect.top && containerRect.bottom > 0;
-          state.transform = diff < 0 ? diff : 0;
-        } else {
-          state.fixed = offset.value > rootRect.top;
-        }
-      } else if (position === 'bottom') {
-        const clientHeight = Taro.getSystemInfoSync().windowHeight;
-        if (container) {
-          const containerRect = await useTaroRect(container, Taro);
-          const diff = clientHeight - containerRect.top - +offset.value - state.height;
-          state.fixed = clientHeight - +offset.value < rootRect.bottom && clientHeight > containerRect.top;
-          state.transform = diff < 0 ? -diff : 0;
-        } else {
-          state.fixed = clientHeight - +offset.value < rootRect.bottom;
-        }
-      }
-
-      emit('scroll', {
-        top: scrollTop,
-        fixed: state.fixed
-      });
-    };
-
-    watch(
-      () => state.fixed,
-      (val) => {
-        emit('change', val);
-      }
-    );
-
-    usePageScroll((res) => {
-      onScroll(res.scrollTop);
-    });
-
-    useReady(() => {
-      Taro.nextTick(() => {
-        onScroll(0);
-      });
-    });
-
     return () => {
       return h(
         'view',
         {
           style: rootStyle.value,
-          id: `root-${refRandomId}`,
           ref: root
         },
         [renderFixed()]

+ 1 - 25
src/sites/mobile-taro/vue/src/layout/pages/sticky/index.vue

@@ -2,28 +2,10 @@
   <div class="demo sticky-demo">
     <h2>基础用法</h2>
     <nut-cell>
-      <nut-sticky top="0">
+      <nut-sticky top="0" :parent-height="1200">
         <nut-button type="primary">吸顶按钮</nut-button>
       </nut-sticky>
     </nut-cell>
-    <h2>吸顶距离</h2>
-    <nut-cell>
-      <nut-sticky top="50">
-        <nut-button type="primary">吸顶距离50px</nut-button>
-      </nut-sticky>
-    </nut-cell>
-    <h2>指定容器</h2>
-    <div class="sticky-container" ref="container" id="container">
-      <nut-sticky top="0" :container="container" z-index="1">
-        <nut-button type="info">指定容器</nut-button>
-      </nut-sticky>
-    </div>
-    <h2>吸底距离</h2>
-    <nut-cell>
-      <nut-sticky bottom="100" position="bottom">
-        <nut-button type="primary">吸底距离100px</nut-button>
-      </nut-sticky>
-    </nut-cell>
   </div>
 </template>
 <script lang="ts">
@@ -39,15 +21,9 @@ export default defineComponent({
 });
 </script>
 <style lang="scss">
-.sticky-demo {
-  height: 200vh !important;
-}
 .sticky-container {
   width: 100%;
   height: 300px;
   background-color: #fff;
 }
-#app {
-  height: auto !important;
-}
 </style>