zz-shopify-components 0.0.21 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/CHANGELOG.md +21 -21
  2. package/README.md +56 -56
  3. package/assets/ScrollTrigger.min.js +11 -11
  4. package/assets/gsap.min.js +11 -11
  5. package/assets/jquery.js +2 -2
  6. package/assets/lazy-video.js +2 -2
  7. package/assets/lazyload.min.js +1 -1
  8. package/assets/lozad.js +10 -10
  9. package/assets/site-jump.js +52 -52
  10. package/assets/site-jumpV2.js +35 -35
  11. package/assets/swiper-bundle.min.css +12 -12
  12. package/assets/swiper-bundle.min.js +13 -13
  13. package/assets/swiper.css +330 -330
  14. package/assets/zz-components.css +322 -322
  15. package/assets/zz-components.js +166 -166
  16. package/assets/zz-fade-in-content.js +169 -169
  17. package/blocks/zz-accessories-item.liquid +188 -188
  18. package/blocks/zz-accessories-swiper.liquid +223 -223
  19. package/blocks/zz-button.liquid +216 -216
  20. package/blocks/zz-content-description-html.liquid +201 -201
  21. package/blocks/zz-content-description.liquid +209 -209
  22. package/blocks/zz-flex-layout-bg-block.liquid +524 -524
  23. package/blocks/zz-flex-layout-block.liquid +548 -548
  24. package/blocks/zz-flex-layout-widget.liquid +321 -321
  25. package/blocks/zz-full-screen-swiper.liquid +447 -447
  26. package/blocks/zz-icon.liquid +46 -46
  27. package/blocks/zz-mail.liquid +135 -135
  28. package/blocks/zz-mb-swiper-pc-flex.liquid +273 -273
  29. package/blocks/zz-price-tag-mini.liquid +100 -106
  30. package/blocks/zz-price-tag.liquid +41 -41
  31. package/blocks/zz-ratio-image.liquid +181 -181
  32. package/blocks/zz-ratio-video.liquid +115 -115
  33. package/blocks/zz-responsive-width-image.liquid +222 -222
  34. package/blocks/zz-responsive-width-video.liquid +166 -166
  35. package/blocks/zz-scroll-animate-bg-text.liquid +268 -268
  36. package/blocks/zz-scroll-cover.liquid +67 -67
  37. package/blocks/zz-tag.liquid +50 -50
  38. package/blocks/zz-text.liquid +227 -227
  39. package/blocks/zz-title.liquid +287 -287
  40. package/blocks/zz-video-button.liquid +84 -84
  41. package/blocks/zz-video-swiper-perview-item.liquid +221 -221
  42. package/blocks/zz-video-swiper-perview.liquid +585 -585
  43. package/component.config.json +7 -7
  44. package/package.json +1 -1
  45. package/scripts/postinstall-v1.js +39 -39
  46. package/scripts/postinstall-v2.js +47 -47
  47. package/scripts/postinstall-v3.js +51 -51
  48. package/scripts/publish-npm.js +43 -43
  49. package/sections/zz-flex-layout-section.liquid +269 -269
  50. package/sections/zz-navigation-tab-v3.liquid +407 -407
  51. package/sections/zz-navigation-tab.liquid +411 -411
  52. package/sections/zz-shopping-card-list.liquid +399 -399
  53. package/sections/zz-video-collapse-swiper.liquid +522 -522
  54. package/sections/zz-video-tab-swiper.liquid +748 -748
  55. package/snippets/zz-button.liquid +70 -70
  56. package/snippets/zz-content-h3.liquid +15 -15
  57. package/snippets/zz-content-text.liquid +56 -56
  58. package/snippets/zz-h2.liquid +31 -31
  59. package/snippets/zz-h3.liquid +31 -31
  60. package/snippets/zz-h4.liquid +30 -30
  61. package/snippets/zz-h5.liquid +39 -39
  62. package/snippets/zz-h6.liquid +39 -39
  63. package/snippets/zz-icon-next.liquid +17 -17
  64. package/snippets/zz-icon-prev.liquid +17 -17
  65. package/snippets/zz-icon.liquid +74 -74
  66. package/snippets/zz-img.liquid +44 -44
  67. package/snippets/zz-prev-next-btn.liquid +62 -62
  68. package/snippets/zz-price-tag.liquid +22 -22
  69. package/snippets/zz-spoke.liquid +142 -142
  70. package/snippets/zz-tag.liquid +22 -22
  71. package/snippets/zz-video-button.liquid +54 -54
  72. package/snippets/zz-video-md.liquid +117 -117
  73. package/snippets/zz-video.liquid +117 -117
@@ -1,166 +1,166 @@
1
- class ZZRadioTabsItem extends HTMLElement {
2
- constructor() {
3
- super();
4
- }
5
-
6
- connectedCallback() {
7
- // 创建radio input
8
- const groupName =
9
- this.closest('zz-radio-tabs')?.getAttribute('name') || 'option';
10
- const type =
11
- this.closest('zz-radio-tabs')?.getAttribute('type') || 'default';
12
- const value = this.getAttribute('value') || '';
13
- const slot = this.innerHTML;
14
- this.innerHTML = `
15
- <label class="zz-radio-tabs-wrapper">
16
- <input type="radio" name=${groupName} value=${value}>
17
- <div class="zz-radio-tabs-label">
18
- ${slot}
19
- </div>
20
- </label>
21
- `;
22
- }
23
- }
24
-
25
- /**
26
- * type: default, black 两种风格模式
27
- */
28
- class ZZRadioTabs extends HTMLElement {
29
- constructor() {
30
- super();
31
- }
32
- connectedCallback() {
33
- // 获取组件的type属性
34
- const type = this.getAttribute('type') || 'default';
35
- // 给自己加class
36
- this.classList.add('zz-radio-tabs');
37
- this.classList.add(`zz-radio-tabs-${type}`);
38
- }
39
-
40
- get value() {
41
- const selectedRadio = this.querySelector('input[type="radio"]:checked');
42
- return selectedRadio?.value;
43
- }
44
-
45
- set value(val) {
46
- const radio = this.querySelector(`input[type="radio"][value="${val}"]`);
47
- if (radio) {
48
- radio.checked = true;
49
- }
50
- }
51
- }
52
-
53
- // 注册自定义元素
54
- customElements.define('zz-radio-tabs-item', ZZRadioTabsItem);
55
- customElements.define('zz-radio-tabs', ZZRadioTabs);
56
-
57
- // 页面加载完成后执行
58
- document.addEventListener('DOMContentLoaded', function () {
59
- // 点击视频播放/暂停
60
- // 在 video 标签上添加 class='click-video-play-pause' 即可
61
- (function () {
62
- const videoPlayAndPause = document.querySelectorAll(
63
- '.click-video-play-pause'
64
- );
65
- videoPlayAndPause.forEach((video) => {
66
- video.classList.remove('video-play-pause');
67
- video.addEventListener('click', function () {
68
- if (this.paused) {
69
- this.play();
70
- } else {
71
- this.pause();
72
- }
73
- });
74
- });
75
- })();
76
- });
77
- /**
78
- * 视频按钮+弹窗
79
- */
80
- class ZZVideoBtn extends HTMLElement {
81
- constructor() {
82
- super();
83
- this.togglePopup = this.togglePopup.bind(this);
84
- this.popup = null;
85
- }
86
-
87
- connectedCallback() {
88
- this.querySelectorAll('.togglePopup').forEach((el) => {
89
- el.addEventListener('click', (event) => {
90
- console.log('click');
91
- if (event.target.tagName !== 'VIDEO') {
92
- this.togglePopup();
93
- }
94
- });
95
- });
96
- this.popup = this.querySelector('.popup');
97
-
98
- if (this.popup) {
99
- // 将 popup 移动到 body
100
- document.body.appendChild(this.popup);
101
- } else {
102
- console.error('Popup element not found.');
103
- }
104
- }
105
-
106
- disconnectedCallback() {
107
- if (this.popup && document.body.contains(this.popup)) {
108
- document.body.removeChild(this.popup); // 清理 popup 元素
109
- }
110
- }
111
-
112
- togglePopup() {
113
- if (!this.popup) return;
114
-
115
- const isHidden = this.popup.classList.contains('!tw-hidden');
116
-
117
- if (isHidden) {
118
- this.showPopup();
119
- } else {
120
- this.hidePopup();
121
- }
122
- }
123
-
124
- showPopup() {
125
- if (!this.popup) return;
126
-
127
- this.popup.classList.remove('!tw-hidden');
128
- gsap.fromTo(
129
- this.popup,
130
- { opacity: 0 },
131
- {
132
- opacity: 1,
133
- duration: 0.3,
134
- ease: 'linear',
135
- backdropFilter: 'blur(30px)',
136
- onComplete: () => {
137
- const video = this.popup.querySelector('video');
138
- if (video) {
139
- video.play();
140
- }
141
- },
142
- }
143
- );
144
- }
145
-
146
- hidePopup() {
147
- if (!this.popup) return;
148
-
149
- gsap.to(this.popup, {
150
- opacity: 0,
151
- duration: 0.3,
152
- ease: 'linear',
153
- onComplete: () => {
154
- this.popup.classList.add('!tw-hidden');
155
- const video = this.popup.querySelector('video');
156
- if (video) {
157
- video.pause();
158
- }
159
- },
160
- });
161
- }
162
- }
163
-
164
- if (!customElements.get('zz-video-button')) {
165
- customElements.define('zz-video-button', ZZVideoBtn);
166
- }
1
+ class ZZRadioTabsItem extends HTMLElement {
2
+ constructor() {
3
+ super();
4
+ }
5
+
6
+ connectedCallback() {
7
+ // 创建radio input
8
+ const groupName =
9
+ this.closest('zz-radio-tabs')?.getAttribute('name') || 'option';
10
+ const type =
11
+ this.closest('zz-radio-tabs')?.getAttribute('type') || 'default';
12
+ const value = this.getAttribute('value') || '';
13
+ const slot = this.innerHTML;
14
+ this.innerHTML = `
15
+ <label class="zz-radio-tabs-wrapper">
16
+ <input type="radio" name=${groupName} value=${value}>
17
+ <div class="zz-radio-tabs-label">
18
+ ${slot}
19
+ </div>
20
+ </label>
21
+ `;
22
+ }
23
+ }
24
+
25
+ /**
26
+ * type: default, black 两种风格模式
27
+ */
28
+ class ZZRadioTabs extends HTMLElement {
29
+ constructor() {
30
+ super();
31
+ }
32
+ connectedCallback() {
33
+ // 获取组件的type属性
34
+ const type = this.getAttribute('type') || 'default';
35
+ // 给自己加class
36
+ this.classList.add('zz-radio-tabs');
37
+ this.classList.add(`zz-radio-tabs-${type}`);
38
+ }
39
+
40
+ get value() {
41
+ const selectedRadio = this.querySelector('input[type="radio"]:checked');
42
+ return selectedRadio?.value;
43
+ }
44
+
45
+ set value(val) {
46
+ const radio = this.querySelector(`input[type="radio"][value="${val}"]`);
47
+ if (radio) {
48
+ radio.checked = true;
49
+ }
50
+ }
51
+ }
52
+
53
+ // 注册自定义元素
54
+ customElements.define('zz-radio-tabs-item', ZZRadioTabsItem);
55
+ customElements.define('zz-radio-tabs', ZZRadioTabs);
56
+
57
+ // 页面加载完成后执行
58
+ document.addEventListener('DOMContentLoaded', function () {
59
+ // 点击视频播放/暂停
60
+ // 在 video 标签上添加 class='click-video-play-pause' 即可
61
+ (function () {
62
+ const videoPlayAndPause = document.querySelectorAll(
63
+ '.click-video-play-pause'
64
+ );
65
+ videoPlayAndPause.forEach((video) => {
66
+ video.classList.remove('video-play-pause');
67
+ video.addEventListener('click', function () {
68
+ if (this.paused) {
69
+ this.play();
70
+ } else {
71
+ this.pause();
72
+ }
73
+ });
74
+ });
75
+ })();
76
+ });
77
+ /**
78
+ * 视频按钮+弹窗
79
+ */
80
+ class ZZVideoBtn extends HTMLElement {
81
+ constructor() {
82
+ super();
83
+ this.togglePopup = this.togglePopup.bind(this);
84
+ this.popup = null;
85
+ }
86
+
87
+ connectedCallback() {
88
+ this.querySelectorAll('.togglePopup').forEach((el) => {
89
+ el.addEventListener('click', (event) => {
90
+ console.log('click');
91
+ if (event.target.tagName !== 'VIDEO') {
92
+ this.togglePopup();
93
+ }
94
+ });
95
+ });
96
+ this.popup = this.querySelector('.popup');
97
+
98
+ if (this.popup) {
99
+ // 将 popup 移动到 body
100
+ document.body.appendChild(this.popup);
101
+ } else {
102
+ console.error('Popup element not found.');
103
+ }
104
+ }
105
+
106
+ disconnectedCallback() {
107
+ if (this.popup && document.body.contains(this.popup)) {
108
+ document.body.removeChild(this.popup); // 清理 popup 元素
109
+ }
110
+ }
111
+
112
+ togglePopup() {
113
+ if (!this.popup) return;
114
+
115
+ const isHidden = this.popup.classList.contains('!tw-hidden');
116
+
117
+ if (isHidden) {
118
+ this.showPopup();
119
+ } else {
120
+ this.hidePopup();
121
+ }
122
+ }
123
+
124
+ showPopup() {
125
+ if (!this.popup) return;
126
+
127
+ this.popup.classList.remove('!tw-hidden');
128
+ gsap.fromTo(
129
+ this.popup,
130
+ { opacity: 0 },
131
+ {
132
+ opacity: 1,
133
+ duration: 0.3,
134
+ ease: 'linear',
135
+ backdropFilter: 'blur(30px)',
136
+ onComplete: () => {
137
+ const video = this.popup.querySelector('video');
138
+ if (video) {
139
+ video.play();
140
+ }
141
+ },
142
+ }
143
+ );
144
+ }
145
+
146
+ hidePopup() {
147
+ if (!this.popup) return;
148
+
149
+ gsap.to(this.popup, {
150
+ opacity: 0,
151
+ duration: 0.3,
152
+ ease: 'linear',
153
+ onComplete: () => {
154
+ this.popup.classList.add('!tw-hidden');
155
+ const video = this.popup.querySelector('video');
156
+ if (video) {
157
+ video.pause();
158
+ }
159
+ },
160
+ });
161
+ }
162
+ }
163
+
164
+ if (!customElements.get('zz-video-button')) {
165
+ customElements.define('zz-video-button', ZZVideoBtn);
166
+ }
@@ -1,169 +1,169 @@
1
- document.addEventListener('DOMContentLoaded', () => {
2
- gsap.registerPlugin(ScrollTrigger);
3
-
4
- // 从下往上显示
5
- (function () {
6
- const fadeDom = document.querySelectorAll('.fade-in-content');
7
- fadeDom.forEach((item) => {
8
- gsap.from(item, {
9
- scrollTrigger: {
10
- trigger: item,
11
- start: 'top 80%',
12
- toggleActions: 'play none none reverse',
13
- once: false, // 动画只播放一次
14
- },
15
- opacity: 0,
16
- y: 80,
17
- duration: 0.4,
18
- ease: 'power2.out',
19
- });
20
- });
21
- })();
22
-
23
- // 从左往右显示
24
- (function () {
25
- const fadeDom = document.querySelectorAll('.fade-in-from-left-content');
26
- fadeDom.forEach((item) => {
27
- gsap.from(item, {
28
- scrollTrigger: {
29
- trigger: item,
30
- start: 'top 80%',
31
- toggleActions: 'play none none reverse',
32
- once: false, // 动画只播放一次
33
- },
34
- opacity: 0,
35
- x: -80,
36
- duration: 0.4,
37
- ease: 'power1.out',
38
- });
39
- });
40
- })();
41
-
42
- // 从右往左显示
43
- (function () {
44
- const fadeDom = document.querySelectorAll('.fade-in-from-right-content');
45
- fadeDom.forEach((item) => {
46
- gsap.from(item, {
47
- scrollTrigger: {
48
- trigger: item,
49
- start: 'top 80%',
50
- toggleActions: 'play none none reverse',
51
- once: false, // 动画只播放一次
52
- },
53
- opacity: 0,
54
- x: 80,
55
- duration: 0.4,
56
- ease: 'power1.out',
57
- });
58
- });
59
- })();
60
-
61
- // 跟随滚动缓慢显示
62
- (function () {
63
- const fadeDom = document.querySelectorAll('.slow-reveal-content');
64
- fadeDom.forEach((item) => {
65
- gsap.from(item, {
66
- scrollTrigger: {
67
- trigger: item,
68
- start: 'top 80%',
69
- end: 'top 60%',
70
- toggleActions: 'play none none reverse',
71
- scrub: 1, // 平滑跟随滚动
72
- },
73
- opacity: 1,
74
- y: 100,
75
- duration: 0.4,
76
- ease: 'power1.out',
77
- });
78
- });
79
- })();
80
-
81
- // 按序从下显示(group)
82
- const el = document.querySelectorAll('.fade-in-box');
83
- el.forEach((item) => {
84
- // 过滤出不包含 no-fade-in 类名的子元素
85
- const children = Array.from(item.children).filter(
86
- (child) => !child.classList.contains('no-fade-in')
87
- );
88
- gsap.from(children, {
89
- scrollTrigger: {
90
- trigger: item,
91
- start: 'top 80%',
92
- toggleActions: 'play none none reverse',
93
- once: false, // 动画只播放一次
94
- },
95
- opacity: 0,
96
- y: 80,
97
- duration: 0.4,
98
- stagger: 0.2,
99
- ease: 'power2.out',
100
- });
101
- });
102
-
103
- // 按序从左进入显示
104
- const fromLeft = document.querySelectorAll('.fade-in-from-left');
105
- fromLeft.forEach((item) => {
106
- // 过滤出不包含 no-fade-in 类名的子元素
107
- const children = Array.from(item.children).filter(
108
- (child) => !child.classList.contains('no-fade-in')
109
- );
110
- gsap.from(children, {
111
- scrollTrigger: {
112
- trigger: item,
113
- start: 'top 80%',
114
- toggleActions: 'play none none reverse',
115
- once: false, // 动画只播放一次
116
- },
117
- opacity: 0,
118
- x: -80,
119
- duration: 0.4,
120
- stagger: 0.1,
121
- ease: 'power1.out',
122
- });
123
- });
124
-
125
- // 按序从右进入显示
126
- const fromRight = document.querySelectorAll('.fade-in-from-right');
127
- fromRight.forEach((item) => {
128
- // 过滤出不包含 no-fade-in 类名的子元素
129
- const children = Array.from(item.children).filter(
130
- (child) => !child.classList.contains('no-fade-in')
131
- );
132
- gsap.from(children, {
133
- scrollTrigger: {
134
- trigger: item,
135
- start: 'top 80%',
136
- toggleActions: 'play none none reverse',
137
- once: false,
138
- },
139
- opacity: 0,
140
- x: 80,
141
- duration: 0.4,
142
- stagger: 0.1,
143
- ease: 'power1.out',
144
- });
145
- });
146
- });
147
-
148
- // 跟随滚动缓慢显示
149
- const slowReveal = document.querySelectorAll('.slow-reveal');
150
- slowReveal.forEach((element) => {
151
- // 过滤出不包含 no-fade-in 类名的子元素
152
- const children = Array.from(element.children).filter(
153
- (child) => !child.classList.contains('no-fade-in')
154
- );
155
- gsap.from(children, {
156
- scrollTrigger: {
157
- trigger: element,
158
- start: 'top 80%',
159
- end: 'top 60%',
160
- scrub: 1, // 平滑跟随滚动
161
- toggleActions: 'play none none reverse',
162
- },
163
- opacity: 1,
164
- y: 100,
165
- duration: 0.4,
166
- stagger: 0.1,
167
- ease: 'power1.out',
168
- });
169
- });
1
+ document.addEventListener('DOMContentLoaded', () => {
2
+ gsap.registerPlugin(ScrollTrigger);
3
+
4
+ // 从下往上显示
5
+ (function () {
6
+ const fadeDom = document.querySelectorAll('.fade-in-content');
7
+ fadeDom.forEach((item) => {
8
+ gsap.from(item, {
9
+ scrollTrigger: {
10
+ trigger: item,
11
+ start: 'top 80%',
12
+ toggleActions: 'play none none reverse',
13
+ once: false, // 动画只播放一次
14
+ },
15
+ opacity: 0,
16
+ y: 80,
17
+ duration: 0.4,
18
+ ease: 'power2.out',
19
+ });
20
+ });
21
+ })();
22
+
23
+ // 从左往右显示
24
+ (function () {
25
+ const fadeDom = document.querySelectorAll('.fade-in-from-left-content');
26
+ fadeDom.forEach((item) => {
27
+ gsap.from(item, {
28
+ scrollTrigger: {
29
+ trigger: item,
30
+ start: 'top 80%',
31
+ toggleActions: 'play none none reverse',
32
+ once: false, // 动画只播放一次
33
+ },
34
+ opacity: 0,
35
+ x: -80,
36
+ duration: 0.4,
37
+ ease: 'power1.out',
38
+ });
39
+ });
40
+ })();
41
+
42
+ // 从右往左显示
43
+ (function () {
44
+ const fadeDom = document.querySelectorAll('.fade-in-from-right-content');
45
+ fadeDom.forEach((item) => {
46
+ gsap.from(item, {
47
+ scrollTrigger: {
48
+ trigger: item,
49
+ start: 'top 80%',
50
+ toggleActions: 'play none none reverse',
51
+ once: false, // 动画只播放一次
52
+ },
53
+ opacity: 0,
54
+ x: 80,
55
+ duration: 0.4,
56
+ ease: 'power1.out',
57
+ });
58
+ });
59
+ })();
60
+
61
+ // 跟随滚动缓慢显示
62
+ (function () {
63
+ const fadeDom = document.querySelectorAll('.slow-reveal-content');
64
+ fadeDom.forEach((item) => {
65
+ gsap.from(item, {
66
+ scrollTrigger: {
67
+ trigger: item,
68
+ start: 'top 80%',
69
+ end: 'top 60%',
70
+ toggleActions: 'play none none reverse',
71
+ scrub: 1, // 平滑跟随滚动
72
+ },
73
+ opacity: 1,
74
+ y: 100,
75
+ duration: 0.4,
76
+ ease: 'power1.out',
77
+ });
78
+ });
79
+ })();
80
+
81
+ // 按序从下显示(group)
82
+ const el = document.querySelectorAll('.fade-in-box');
83
+ el.forEach((item) => {
84
+ // 过滤出不包含 no-fade-in 类名的子元素
85
+ const children = Array.from(item.children).filter(
86
+ (child) => !child.classList.contains('no-fade-in')
87
+ );
88
+ gsap.from(children, {
89
+ scrollTrigger: {
90
+ trigger: item,
91
+ start: 'top 80%',
92
+ toggleActions: 'play none none reverse',
93
+ once: false, // 动画只播放一次
94
+ },
95
+ opacity: 0,
96
+ y: 80,
97
+ duration: 0.4,
98
+ stagger: 0.2,
99
+ ease: 'power2.out',
100
+ });
101
+ });
102
+
103
+ // 按序从左进入显示
104
+ const fromLeft = document.querySelectorAll('.fade-in-from-left');
105
+ fromLeft.forEach((item) => {
106
+ // 过滤出不包含 no-fade-in 类名的子元素
107
+ const children = Array.from(item.children).filter(
108
+ (child) => !child.classList.contains('no-fade-in')
109
+ );
110
+ gsap.from(children, {
111
+ scrollTrigger: {
112
+ trigger: item,
113
+ start: 'top 80%',
114
+ toggleActions: 'play none none reverse',
115
+ once: false, // 动画只播放一次
116
+ },
117
+ opacity: 0,
118
+ x: -80,
119
+ duration: 0.4,
120
+ stagger: 0.1,
121
+ ease: 'power1.out',
122
+ });
123
+ });
124
+
125
+ // 按序从右进入显示
126
+ const fromRight = document.querySelectorAll('.fade-in-from-right');
127
+ fromRight.forEach((item) => {
128
+ // 过滤出不包含 no-fade-in 类名的子元素
129
+ const children = Array.from(item.children).filter(
130
+ (child) => !child.classList.contains('no-fade-in')
131
+ );
132
+ gsap.from(children, {
133
+ scrollTrigger: {
134
+ trigger: item,
135
+ start: 'top 80%',
136
+ toggleActions: 'play none none reverse',
137
+ once: false,
138
+ },
139
+ opacity: 0,
140
+ x: 80,
141
+ duration: 0.4,
142
+ stagger: 0.1,
143
+ ease: 'power1.out',
144
+ });
145
+ });
146
+ });
147
+
148
+ // 跟随滚动缓慢显示
149
+ const slowReveal = document.querySelectorAll('.slow-reveal');
150
+ slowReveal.forEach((element) => {
151
+ // 过滤出不包含 no-fade-in 类名的子元素
152
+ const children = Array.from(element.children).filter(
153
+ (child) => !child.classList.contains('no-fade-in')
154
+ );
155
+ gsap.from(children, {
156
+ scrollTrigger: {
157
+ trigger: element,
158
+ start: 'top 80%',
159
+ end: 'top 60%',
160
+ scrub: 1, // 平滑跟随滚动
161
+ toggleActions: 'play none none reverse',
162
+ },
163
+ opacity: 1,
164
+ y: 100,
165
+ duration: 0.4,
166
+ stagger: 0.1,
167
+ ease: 'power1.out',
168
+ });
169
+ });