@xwadex/fesd 0.0.1
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.
- package/20240328-video4-setting.png +0 -0
- package/CHANGELOG.md +41 -0
- package/README.md +25 -0
- package/dist/assets/fesd-bundle.css +9 -0
- package/dist/assets/fesd-bundle.js +9800 -0
- package/dist/assets/fesd-bundle.js.map +1 -0
- package/index.html +25 -0
- package/package.json +23 -0
- package/prepros.config +883 -0
- package/src/fesd/anchor4/anchor4.js +179 -0
- package/src/fesd/aost4/_aost4.sass +64 -0
- package/src/fesd/aost4/aost4.js +138 -0
- package/src/fesd/article4/article4.js +280 -0
- package/src/fesd/article4/article4.md +1 -0
- package/src/fesd/category-slider/_category-slider.sass +33 -0
- package/src/fesd/category-slider/category-slider.js +332 -0
- package/src/fesd/collapse4/collapse4.js +159 -0
- package/src/fesd/detect4/detect4.js +70 -0
- package/src/fesd/dropdown4/_dropdown4.sass +185 -0
- package/src/fesd/dropdown4/cityData.js +830 -0
- package/src/fesd/dropdown4/dropdown4.js +647 -0
- package/src/fesd/image-preview/_image-preview.sass +26 -0
- package/src/fesd/image-preview/image-preview.js +209 -0
- package/src/fesd/image-validate/_image-validate.sass +21 -0
- package/src/fesd/image-validate/image-validate.js +84 -0
- package/src/fesd/marquee4/_marquee4.sass +45 -0
- package/src/fesd/marquee4/marquee4.js +371 -0
- package/src/fesd/modal4/_modal4.sass +134 -0
- package/src/fesd/modal4/modal4.js +236 -0
- package/src/fesd/modal4/modernModal.js +182 -0
- package/src/fesd/multipurpose4/_multipurpose4.sass +282 -0
- package/src/fesd/multipurpose4/multipurpose4.js +562 -0
- package/src/fesd/ripple4/_ripple4.sass +44 -0
- package/src/fesd/ripple4/ripple4.js +138 -0
- package/src/fesd/share4/share4.js +191 -0
- package/src/fesd/shared/shared.js +59 -0
- package/src/fesd/shared/utils.js +98 -0
- package/src/fesd/tab4/_tab4.sass +25 -0
- package/src/fesd/tab4/tab4.js +473 -0
- package/src/fesd/video4/README.md +3 -0
- package/src/fesd/video4/_video4.sass +117 -0
- package/src/fesd/video4/video4.js +237 -0
- package/src/fesd/video4/videoPlayer.js +195 -0
- package/src/fesd.js +53 -0
- package/src/fesd.sass +29 -0
- package/src/fesdDB.js +282 -0
- package/vite.config.js +37 -0
@@ -0,0 +1,179 @@
|
|
1
|
+
import SHARED from './../shared/shared';
|
2
|
+
import { isString, isElementExist, isFunction, getElement, getAllElements } from './../shared/utils';
|
3
|
+
|
4
|
+
const ease = {
|
5
|
+
easeInOutCirc(t, b, c, d) {
|
6
|
+
if ((t /= d / 2) < 1) return (-c / 2) * (Math.sqrt(1 - t * t) - 1) + b;
|
7
|
+
return (c / 2) * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
|
8
|
+
},
|
9
|
+
easeInQuart(t, b, c, d) {
|
10
|
+
return c * (t /= d) * t * t * t + b;
|
11
|
+
},
|
12
|
+
easeOutQuart(t, b, c, d) {
|
13
|
+
return -c * ((t = t / d - 1) * t * t * t - 1) + b;
|
14
|
+
},
|
15
|
+
};
|
16
|
+
|
17
|
+
// scroll handler
|
18
|
+
const scrollTo = (options, instance) => {
|
19
|
+
const { target, container, spacer, speed, gap, easing, direction } = options;
|
20
|
+
|
21
|
+
const isHorizontal = direction === 'horizontal';
|
22
|
+
const scrollDirection = isHorizontal ? 'scrollLeft' : 'scrollTop';
|
23
|
+
const rectPosition = isHorizontal ? 'left' : 'top';
|
24
|
+
const rectSpace = isHorizontal ? 'width' : 'height';
|
25
|
+
|
26
|
+
const containerEle = isElementExist(container) ? getElement(container) : document.scrollingElement;
|
27
|
+
const start = containerEle[scrollDirection];
|
28
|
+
const targetPoint = isElementExist(target) ? getElement(target).getBoundingClientRect()[rectPosition] : 0 - start;
|
29
|
+
const spacerGap = isElementExist(spacer) ? getElement(spacer).getBoundingClientRect()[rectSpace] : 0;
|
30
|
+
const change = targetPoint - gap - spacerGap;
|
31
|
+
const increment = 15;
|
32
|
+
let currentTime = 0;
|
33
|
+
|
34
|
+
if (change === 0) return;
|
35
|
+
|
36
|
+
const emitEvent = eventName => {
|
37
|
+
const targetEle = getElement(target);
|
38
|
+
if (instance) instance.emit(eventName, targetEle);
|
39
|
+
if (!instance && options.on) {
|
40
|
+
if (isFunction(options.on[eventName])) options.on[eventName](targetEle);
|
41
|
+
}
|
42
|
+
};
|
43
|
+
|
44
|
+
emitEvent('beforeScroll');
|
45
|
+
|
46
|
+
const animateScroll = () => {
|
47
|
+
currentTime += increment;
|
48
|
+
const val = ease[easing](currentTime, start, change, speed);
|
49
|
+
containerEle[scrollDirection] = val;
|
50
|
+
if (currentTime < speed) requestAnimationFrame(animateScroll);
|
51
|
+
if (currentTime >= speed) emitEvent('afterScroll');
|
52
|
+
};
|
53
|
+
|
54
|
+
requestAnimationFrame(animateScroll);
|
55
|
+
};
|
56
|
+
|
57
|
+
// class Anchor4
|
58
|
+
class Anchor4 {
|
59
|
+
constructor(el, options = {}) {
|
60
|
+
this.__storage__ = {
|
61
|
+
el,
|
62
|
+
options,
|
63
|
+
};
|
64
|
+
|
65
|
+
this.#create();
|
66
|
+
}
|
67
|
+
|
68
|
+
#create() {
|
69
|
+
const { el, options } = this.__storage__;
|
70
|
+
if (!isString(el) || !isElementExist(el)) return;
|
71
|
+
|
72
|
+
const { SETTINGS, EVENTS } = fesdDB.anchor4;
|
73
|
+
|
74
|
+
this.elements = getAllElements(el);
|
75
|
+
this.options = Object.assign({}, SETTINGS, options);
|
76
|
+
this.__events__ = Object.assign({}, EVENTS);
|
77
|
+
|
78
|
+
if (this.options.on) {
|
79
|
+
for (const [k, v] of Object.entries(this.options.on)) {
|
80
|
+
this.__events__[k] = [v];
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
this.#init();
|
85
|
+
}
|
86
|
+
|
87
|
+
#init() {
|
88
|
+
const { elements, options } = this;
|
89
|
+
|
90
|
+
elements.forEach(el => {
|
91
|
+
el.anchor = {};
|
92
|
+
el.anchor.instance = this;
|
93
|
+
el.anchor.eventHandler = this.#trigger;
|
94
|
+
el.anchor.defaultOptions = options;
|
95
|
+
el.addEventListener('click', el.anchor.eventHandler);
|
96
|
+
});
|
97
|
+
|
98
|
+
this.emit('afterInit');
|
99
|
+
}
|
100
|
+
|
101
|
+
#trigger() {
|
102
|
+
/** the keyword `this` in this method is pointed to the click target */
|
103
|
+
const { defaultOptions, eventHandler, instance } = this.anchor;
|
104
|
+
|
105
|
+
const options = {
|
106
|
+
target: this.getAttribute('data-anchor-target') || defaultOptions.target,
|
107
|
+
container: this.getAttribute('data-anchor-container') || defaultOptions.container,
|
108
|
+
spacer: this.getAttribute('data-anchor-spacer') || defaultOptions.spacer,
|
109
|
+
gap: parseInt(this.getAttribute('data-anchor-gap') || defaultOptions.gap),
|
110
|
+
speed: parseInt(this.getAttribute('data-anchor-speed')) || defaultOptions.speed,
|
111
|
+
delay: parseInt(this.getAttribute('data-anchor-delay')) || defaultOptions.delay,
|
112
|
+
easing: this.getAttribute('data-anchor-easing') || defaultOptions.easing,
|
113
|
+
direction: this.getAttribute('data-anchor-direction') || defaultOptions.direction,
|
114
|
+
};
|
115
|
+
|
116
|
+
// prevent multiple click
|
117
|
+
this.removeEventListener('click', eventHandler);
|
118
|
+
setTimeout(() => {
|
119
|
+
this.addEventListener('click', eventHandler);
|
120
|
+
}, options.speed);
|
121
|
+
|
122
|
+
// do scroll
|
123
|
+
setTimeout(() => {
|
124
|
+
scrollTo(options, instance);
|
125
|
+
}, options.delay);
|
126
|
+
}
|
127
|
+
|
128
|
+
destroy() {
|
129
|
+
const { elements } = this;
|
130
|
+
|
131
|
+
this.emit('beforeDestroy');
|
132
|
+
|
133
|
+
elements.forEach(el => {
|
134
|
+
if (!el.anchor) return;
|
135
|
+
|
136
|
+
el.removeEventListener('click', el.anchor.eventHandler);
|
137
|
+
delete el.anchor;
|
138
|
+
});
|
139
|
+
|
140
|
+
return this;
|
141
|
+
}
|
142
|
+
|
143
|
+
update() {
|
144
|
+
this.destroy().#create();
|
145
|
+
|
146
|
+
this.emit('afterUpdate');
|
147
|
+
|
148
|
+
return this;
|
149
|
+
}
|
150
|
+
|
151
|
+
static run(options) {
|
152
|
+
const { SETTINGS } = fesdDB.anchor4;
|
153
|
+
const newOptions = Object.assign({}, SETTINGS, options);
|
154
|
+
|
155
|
+
setTimeout(() => {
|
156
|
+
scrollTo(newOptions);
|
157
|
+
}, newOptions.delay);
|
158
|
+
}
|
159
|
+
|
160
|
+
static url(options) {
|
161
|
+
const { SETTINGS } = fesdDB.anchor4;
|
162
|
+
|
163
|
+
const targetStr = window.location.search || window.location.hash;
|
164
|
+
const targetName = targetStr.split('?').pop();
|
165
|
+
const target = document.querySelector(`[data-anchor-id="${targetName}"]`);
|
166
|
+
|
167
|
+
if (!target) return;
|
168
|
+
|
169
|
+
const newOptions = Object.assign({}, SETTINGS, options, { target });
|
170
|
+
|
171
|
+
setTimeout(() => {
|
172
|
+
scrollTo(newOptions);
|
173
|
+
}, newOptions.delay);
|
174
|
+
}
|
175
|
+
}
|
176
|
+
|
177
|
+
Object.assign(Anchor4.prototype, SHARED);
|
178
|
+
|
179
|
+
export default Anchor4;
|
@@ -0,0 +1,64 @@
|
|
1
|
+
// aost
|
2
|
+
[data-aost]
|
3
|
+
// animations
|
4
|
+
&[data-aost-fade]
|
5
|
+
opacity: 0
|
6
|
+
&.aost-show
|
7
|
+
opacity: 1
|
8
|
+
transition: opacity var(--aost-trans, .8s)
|
9
|
+
&[data-aost-fade-up]
|
10
|
+
opacity: 0
|
11
|
+
transform: translateY(50px)
|
12
|
+
&.aost-show
|
13
|
+
opacity: 1
|
14
|
+
transform: translateY(0)
|
15
|
+
transition: opacity var(--aost-trans, .8s), transform var(--aost-trans, .8s)
|
16
|
+
&[data-aost-fade-down]
|
17
|
+
opacity: 0
|
18
|
+
transform: translateY(-50px)
|
19
|
+
&.aost-show
|
20
|
+
opacity: 1
|
21
|
+
transform: translateY(0)
|
22
|
+
transition: opacity var(--aost-trans, .8s), transform var(--aost-trans, .8s)
|
23
|
+
&[data-aost-fade-right]
|
24
|
+
opacity: 0
|
25
|
+
transform: translateX(50px)
|
26
|
+
&.aost-show
|
27
|
+
opacity: 1
|
28
|
+
transform: translateY(0)
|
29
|
+
transition: opacity var(--aost-trans, .8s), transform var(--aost-trans, .8s)
|
30
|
+
&[data-aost-fade-left]
|
31
|
+
opacity: 0
|
32
|
+
transform: translateX(-50px)
|
33
|
+
&.aost-show
|
34
|
+
opacity: 1
|
35
|
+
transform: translateY(0)
|
36
|
+
transition: opacity var(--aost-trans, .8s), transform var(--aost-trans, .8s)
|
37
|
+
&[data-aost-clip-down]
|
38
|
+
opacity: 0
|
39
|
+
clip-path: polygon(0 0, 100% 0, 100% 0, 0 0)
|
40
|
+
&.aost-show
|
41
|
+
opacity: 1
|
42
|
+
clip-path: polygon(0 0, 100% 0, 100% 115%, 0 100%)
|
43
|
+
transition: opacity var(--aost-trans, .8s), clip-path var(--aost-trans, .8s)
|
44
|
+
&[data-aost-clip-left]
|
45
|
+
opacity: 0
|
46
|
+
clip-path: polygon(0 0, 0 0, 0 100%, 0 100%)
|
47
|
+
&.aost-show
|
48
|
+
opacity: 1
|
49
|
+
clip-path: polygon(0 0, 110% 0, 100% 100%, 0 100%)
|
50
|
+
transition: opacity var(--aost-trans, .8s), clip-path var(--aost-trans, .8s)
|
51
|
+
&[data-aost-clip-right]
|
52
|
+
opacity: 0
|
53
|
+
clip-path: polygon(100% 0, 100% 0, 100% 100%, 100% 100%)
|
54
|
+
&.aost-show
|
55
|
+
opacity: 1
|
56
|
+
clip-path: polygon(-10% 0, 100% 0, 100% 100%, 0% 100%)
|
57
|
+
transition: opacity var(--aost-trans, .8s), clip-path var(--aost-trans, .8s)
|
58
|
+
&[data-aost-scale]
|
59
|
+
opacity: 0
|
60
|
+
transform: scale(.5)
|
61
|
+
&.aost-show
|
62
|
+
opacity: 1
|
63
|
+
transform: scale(1)
|
64
|
+
transition: opacity var(--aost-trans, .8s), clip-path var(--aost-trans, .8s)
|
@@ -0,0 +1,138 @@
|
|
1
|
+
import SHARED from './../shared/shared';
|
2
|
+
import { isString, isElementExist, getElement, getAllElements } from './../shared/utils';
|
3
|
+
|
4
|
+
const interaction = (scrollElement, elements) => {
|
5
|
+
const viewHeight = scrollElement === window ? scrollElement.innerHeight : scrollElement.getBoundingClientRect().height;
|
6
|
+
const viewTop = scrollElement === window ? 0 : scrollElement.getBoundingClientRect().top;
|
7
|
+
|
8
|
+
elements.forEach(el => {
|
9
|
+
const { class: className, delay, start, end, repeat, instance } = el.aost;
|
10
|
+
|
11
|
+
const { top, bottom } = el.getBoundingClientRect();
|
12
|
+
const startTrigger = viewHeight * (start / 100);
|
13
|
+
const endTrigger = viewHeight * (end / 100);
|
14
|
+
const isEntered = top - viewTop <= startTrigger && bottom - viewTop >= endTrigger;
|
15
|
+
|
16
|
+
// in view
|
17
|
+
if (isEntered && el.offsetParent) {
|
18
|
+
setTimeout(() => {
|
19
|
+
// instance.emit('enter', el);
|
20
|
+
el.classList.add(className);
|
21
|
+
}, delay);
|
22
|
+
}
|
23
|
+
// out of view
|
24
|
+
else {
|
25
|
+
const shouldRemove = (el.classList.contains(className) && repeat === 'down' && top - viewTop >= startTrigger) || (repeat === 'up' && bottom - viewTop <= endTrigger) || repeat === true;
|
26
|
+
setTimeout(() => {
|
27
|
+
// instance.emit('leave', el);
|
28
|
+
if (shouldRemove) el.classList.remove(className);
|
29
|
+
}, delay);
|
30
|
+
}
|
31
|
+
});
|
32
|
+
};
|
33
|
+
|
34
|
+
const detectRepeat = (repeatType, options) => {
|
35
|
+
if (repeatType === 'up' || repeatType === 'down') {
|
36
|
+
return repeatType;
|
37
|
+
}
|
38
|
+
|
39
|
+
if (repeatType !== null) {
|
40
|
+
if (repeatType === 'true') {
|
41
|
+
return true;
|
42
|
+
} else if (repeatType === 'false') {
|
43
|
+
return false;
|
44
|
+
} else {
|
45
|
+
return options.repeat;
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
return options.repeat;
|
50
|
+
};
|
51
|
+
|
52
|
+
class Aost4 {
|
53
|
+
constructor(el, options = {}) {
|
54
|
+
this.__storage__ = {
|
55
|
+
el,
|
56
|
+
options,
|
57
|
+
};
|
58
|
+
|
59
|
+
this.#create();
|
60
|
+
}
|
61
|
+
|
62
|
+
#create() {
|
63
|
+
const { el, options } = this.__storage__;
|
64
|
+
if (!isString(el) || !isElementExist(el)) return;
|
65
|
+
|
66
|
+
const { SETTINGS, EVENTS } = fesdDB.aost4;
|
67
|
+
|
68
|
+
this.elements = getAllElements(el);
|
69
|
+
this.options = Object.assign({}, SETTINGS, options);
|
70
|
+
this.__events__ = Object.assign({}, EVENTS);
|
71
|
+
|
72
|
+
if (this.options.on) {
|
73
|
+
for (const [k, v] of Object.entries(this.options.on)) {
|
74
|
+
this.__events__[k] = [v];
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
this.#init();
|
79
|
+
}
|
80
|
+
|
81
|
+
#init() {
|
82
|
+
const { elements, options } = this;
|
83
|
+
const { scroller } = options;
|
84
|
+
const scrollElement = scroller === window || !isElementExist(scroller) ? window : getElement(scroller);
|
85
|
+
|
86
|
+
this.eventHandler = () => {
|
87
|
+
interaction(scrollElement, elements);
|
88
|
+
};
|
89
|
+
|
90
|
+
elements.forEach(el => {
|
91
|
+
el.aost = {};
|
92
|
+
el.aost.class = el.getAttribute('data-aost-class') || options.class;
|
93
|
+
el.aost.delay = parseInt(el.getAttribute('data-aost-delay')) || options.delay;
|
94
|
+
el.aost.start = parseInt(el.getAttribute('data-aost-start')) || options.start;
|
95
|
+
el.aost.end = parseInt(el.getAttribute('data-aost-end')) || options.end;
|
96
|
+
el.aost.repeat = detectRepeat(el.getAttribute('data-aost-repeat'), options);
|
97
|
+
el.aost.instance = this;
|
98
|
+
});
|
99
|
+
|
100
|
+
const { eventHandler } = this;
|
101
|
+
eventHandler();
|
102
|
+
scrollElement.aost = {};
|
103
|
+
scrollElement.aost.eventHandler = eventHandler;
|
104
|
+
scrollElement.addEventListener('scroll', scrollElement.aost.eventHandler, false);
|
105
|
+
}
|
106
|
+
|
107
|
+
destroy(removeShow) {
|
108
|
+
const { elements, options } = this;
|
109
|
+
if (!elements) return this;
|
110
|
+
|
111
|
+
const { scroller } = options;
|
112
|
+
const scrollElement = scroller === window || !isElementExist(scroller) ? window : getElement(scroller);
|
113
|
+
|
114
|
+
if (scrollElement.aost) {
|
115
|
+
scrollElement.removeEventListener('scroll', scrollElement.aost.eventHandler);
|
116
|
+
delete scrollElement.aost;
|
117
|
+
}
|
118
|
+
|
119
|
+
elements.forEach(el => {
|
120
|
+
if (!el.aost) return;
|
121
|
+
const { class: className } = el.aost;
|
122
|
+
if (removeShow) {
|
123
|
+
el.classList.remove(className);
|
124
|
+
}
|
125
|
+
delete el.aost;
|
126
|
+
});
|
127
|
+
|
128
|
+
return this;
|
129
|
+
}
|
130
|
+
|
131
|
+
update(removeShow) {
|
132
|
+
this.destroy(removeShow).#create();
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
Object.assign(Aost4.prototype, SHARED);
|
137
|
+
|
138
|
+
export default Aost4;
|
@@ -0,0 +1,280 @@
|
|
1
|
+
// import Swiper bundle with all modules installed
|
2
|
+
import { Swiper as SwiperV8 } from 'swiper/bundle';
|
3
|
+
import { isString, isNodeList, isElementExist, getAllElements, createUid } from './../shared/utils';
|
4
|
+
|
5
|
+
('use strict');
|
6
|
+
|
7
|
+
// 設置 CSS 樣式
|
8
|
+
const setCss = (target, style, css) => {
|
9
|
+
if (!target) return;
|
10
|
+
|
11
|
+
// 若是 NodeList 則需使用 foreach set css
|
12
|
+
if (isNodeList(target)) target.forEach(el => (el.style[style] = css));
|
13
|
+
else target.style[style] = css;
|
14
|
+
};
|
15
|
+
|
16
|
+
class Article4 {
|
17
|
+
constructor(el, options = {}) {
|
18
|
+
if (!isString(el) || !isElementExist(el)) return;
|
19
|
+
|
20
|
+
this.__storage__ = {
|
21
|
+
el,
|
22
|
+
options,
|
23
|
+
};
|
24
|
+
|
25
|
+
this.#create();
|
26
|
+
}
|
27
|
+
|
28
|
+
#create() {
|
29
|
+
const { el, options } = this.__storage__;
|
30
|
+
const { SETTINGS } = fesdDB.article4;
|
31
|
+
|
32
|
+
this.elements = getAllElements(el);
|
33
|
+
this.options = Object.assign({}, SETTINGS, options);
|
34
|
+
|
35
|
+
this.#init();
|
36
|
+
}
|
37
|
+
|
38
|
+
#init() {
|
39
|
+
const { elements } = this;
|
40
|
+
|
41
|
+
elements.forEach(parent => {
|
42
|
+
parent.querySelectorAll('._article').forEach(el => {
|
43
|
+
el.article = {};
|
44
|
+
el.article.parent = parent;
|
45
|
+
el.article.params = this.#getArticleData(el);
|
46
|
+
|
47
|
+
this.#setStyle(el).#createVideo4(el).#createSwiper(el);
|
48
|
+
});
|
49
|
+
});
|
50
|
+
}
|
51
|
+
|
52
|
+
// 取得元件上的設定值
|
53
|
+
#getArticleData(element) {
|
54
|
+
return {
|
55
|
+
// 元件本身
|
56
|
+
$selector: element,
|
57
|
+
|
58
|
+
// 父層元件
|
59
|
+
$backgroundWrap: element.querySelector('._backgroundWrap'),
|
60
|
+
$contentWrap: element.querySelector('._contentWrap'),
|
61
|
+
$wordCover: element.querySelector('._wordCover'),
|
62
|
+
$buttonCover: element.querySelector('._buttonCover'),
|
63
|
+
$imgCover: element.querySelector('._imgCover'),
|
64
|
+
$cover: element.querySelectorAll('._cover'),
|
65
|
+
$swiper: element.querySelector('.swiper'),
|
66
|
+
$swiperButtonCover: element.querySelector('.swiper-button-cover'),
|
67
|
+
|
68
|
+
// 子層元件
|
69
|
+
$h: element.querySelector('._H'),
|
70
|
+
$subH: element.querySelector('._subH'),
|
71
|
+
$p: element.querySelector('._P'),
|
72
|
+
$button: element.querySelector('._button'),
|
73
|
+
$description: element.querySelectorAll('._description'),
|
74
|
+
$video: element.querySelectorAll('[video-id]'),
|
75
|
+
|
76
|
+
// 父層設定
|
77
|
+
typeFullColor: element.getAttribute('typeFull-color'),
|
78
|
+
typeFullBoxColor: element.getAttribute('typeFull-boxcolor'),
|
79
|
+
|
80
|
+
// 子層設定
|
81
|
+
hColor: element.getAttribute('h-color'),
|
82
|
+
subHColor: element.getAttribute('subh-color'),
|
83
|
+
pColor: element.getAttribute('p-color'),
|
84
|
+
buttonColor: element.getAttribute('button-color'),
|
85
|
+
buttonColorHover: element.getAttribute('button-color-hover'),
|
86
|
+
buttonTextColor: element.getAttribute('button-textcolor'),
|
87
|
+
descriptionColor: element.getAttribute('description-color'),
|
88
|
+
};
|
89
|
+
}
|
90
|
+
|
91
|
+
// 設置設定值的 CSS 樣式
|
92
|
+
#setStyle(element) {
|
93
|
+
const { params } = element.article;
|
94
|
+
|
95
|
+
// article ._H
|
96
|
+
setCss(params.$h, 'color', params.hColor);
|
97
|
+
|
98
|
+
// article ._subH
|
99
|
+
setCss(params.$subH, 'color', params.subHColor);
|
100
|
+
|
101
|
+
// article ._P
|
102
|
+
setCss(params.$p, 'color', params.pColor);
|
103
|
+
|
104
|
+
// imgCover ._description
|
105
|
+
setCss(params.$description, 'color', params.descriptionColor);
|
106
|
+
|
107
|
+
// button background-color && text color
|
108
|
+
setCss(params.$button, 'backgroundColor', params.buttonColor);
|
109
|
+
setCss(params.$button, 'color', params.buttonTextColor);
|
110
|
+
|
111
|
+
// button hover color
|
112
|
+
if (params.buttonColorHover) {
|
113
|
+
params.$button.appendChild(document.createElement('span'));
|
114
|
+
setCss(params.$button.querySelector('span'), 'backgroundColor', params.buttonColorHover);
|
115
|
+
}
|
116
|
+
|
117
|
+
// typeFull background-color
|
118
|
+
setCss(params.$backgroundWrap, 'backgroundColor', params.typeFullColor);
|
119
|
+
|
120
|
+
// typeFull box background-color
|
121
|
+
setCss(params.$contentWrap, 'backgroundColor', params.typeFullBoxColor);
|
122
|
+
|
123
|
+
return this;
|
124
|
+
}
|
125
|
+
|
126
|
+
#createVideo4(element) {
|
127
|
+
const { params } = element.article;
|
128
|
+
|
129
|
+
if (params.$video.length) {
|
130
|
+
const video = new Video4(params.$video);
|
131
|
+
}
|
132
|
+
|
133
|
+
return this;
|
134
|
+
}
|
135
|
+
|
136
|
+
#createSwiper(element) {
|
137
|
+
const { basic_rwd } = this.options;
|
138
|
+
|
139
|
+
const { params } = element.article;
|
140
|
+
|
141
|
+
// 判斷是否擁有 swiper4 結構
|
142
|
+
if (!params.$swiper) return;
|
143
|
+
|
144
|
+
// set id
|
145
|
+
const $id = createUid();
|
146
|
+
|
147
|
+
const $this = this;
|
148
|
+
|
149
|
+
// set swiper
|
150
|
+
let $swiperSet = {
|
151
|
+
on: {
|
152
|
+
init(swiper) {
|
153
|
+
const container = swiper.$el[0];
|
154
|
+
// video4 重複綁定修正
|
155
|
+
if (params.$video.length) {
|
156
|
+
// 應該抓 DB 設定的 classname
|
157
|
+
const allVideo4 = container.querySelectorAll('[video4-active]');
|
158
|
+
[...allVideo4].forEach(element => {
|
159
|
+
element.querySelector(fesdDB.video4.SETTINGS.videoButton)?.remove();
|
160
|
+
element.querySelector('.overlay')?.remove();
|
161
|
+
element.removeAttribute('video4-active');
|
162
|
+
});
|
163
|
+
$this.update();
|
164
|
+
}
|
165
|
+
},
|
166
|
+
observerUpdate(swiper) {
|
167
|
+
if (swiper.params.autoplay.enabled) {
|
168
|
+
swiper.autoplay.start();
|
169
|
+
swiper.update();
|
170
|
+
}
|
171
|
+
},
|
172
|
+
},
|
173
|
+
observer: true,
|
174
|
+
breakpoints: {},
|
175
|
+
};
|
176
|
+
|
177
|
+
params.$selector.setAttribute('img-swiper', 'on');
|
178
|
+
params.$selector.classList.add(`swiper-${$id}`);
|
179
|
+
|
180
|
+
// swiper navigation (預設為 off)
|
181
|
+
if (params.$selector.getAttribute('swiper-arrow') !== 'off' && params.$selector.getAttribute('swiper-arrow')) {
|
182
|
+
const next = document.createElement('div');
|
183
|
+
next.className = `swiper-button-next swiper-${$id}`;
|
184
|
+
params.$swiperButtonCover.appendChild(next);
|
185
|
+
|
186
|
+
const prev = document.createElement('div');
|
187
|
+
prev.className = `swiper-button-prev swiper-${$id}`;
|
188
|
+
params.$swiperButtonCover.appendChild(prev);
|
189
|
+
|
190
|
+
$swiperSet.navigation = {
|
191
|
+
nextEl: `.swiper-button-next.swiper-${$id}`,
|
192
|
+
prevEl: `.swiper-button-prev.swiper-${$id}`,
|
193
|
+
};
|
194
|
+
}
|
195
|
+
|
196
|
+
// swiper pagination (預設為 on)
|
197
|
+
if (params.$selector.getAttribute('swiper-nav') !== 'off' || !params.$selector.getAttribute('swiper-nav')) {
|
198
|
+
const pagination = document.createElement('div');
|
199
|
+
pagination.className = `swiper-pagination swiper-${$id}`;
|
200
|
+
params.$swiper.appendChild(pagination);
|
201
|
+
|
202
|
+
$swiperSet.pagination = {
|
203
|
+
el: `.swiper-pagination.swiper-${$id}`,
|
204
|
+
clickable: true,
|
205
|
+
};
|
206
|
+
}
|
207
|
+
|
208
|
+
// slidesPerView
|
209
|
+
if (Number.parseInt(params.$selector.getAttribute('swiper-num'))) {
|
210
|
+
$swiperSet.breakpoints[basic_rwd] = {
|
211
|
+
slidesPerView: params.$selector.getAttribute('swiper-num') ? (Number.parseInt(params.$selector.getAttribute('swiper-num')) > 5 ? 5 : Number.parseInt(params.$selector.getAttribute('swiper-num'))) : 1,
|
212
|
+
};
|
213
|
+
}
|
214
|
+
|
215
|
+
// autoplay (預設為 on)
|
216
|
+
if (params.$selector.getAttribute('swiper-autoplay') !== 'off' || !params.$selector.getAttribute('swiper-autoplay')) {
|
217
|
+
$swiperSet.autoplay = {
|
218
|
+
delay: 3000,
|
219
|
+
disableOnInteraction: false,
|
220
|
+
};
|
221
|
+
}
|
222
|
+
|
223
|
+
// loop (預設為 on)
|
224
|
+
if (params.$selector.getAttribute('swiper-loop') !== 'off' || !params.$selector.getAttribute('swiper-loop')) {
|
225
|
+
$swiperSet.loop = true;
|
226
|
+
}
|
227
|
+
|
228
|
+
// speed
|
229
|
+
if (params.$selector.getAttribute('swiper-speed')) {
|
230
|
+
$swiperSet.speed = parseInt(params.$selector.getAttribute('swiper-speed'));
|
231
|
+
}
|
232
|
+
|
233
|
+
// parallax (預設為 off)
|
234
|
+
if (params.$selector.getAttribute('swiper-parallax') !== 'off' && !params.$selector.getAttribute('swiper-loop')) {
|
235
|
+
$swiperSet.parallax = true;
|
236
|
+
}
|
237
|
+
|
238
|
+
// pagination dynamicBullets (預設為 off)
|
239
|
+
if (params.$selector.getAttribute('swiper-pagination-dynamic') === 'on') {
|
240
|
+
$swiperSet.pagination.dynamicBullets = true;
|
241
|
+
}
|
242
|
+
|
243
|
+
// 若 swiper 只有一筆輪播則隱藏 navigation 及 pagination
|
244
|
+
let gate = () => (window.innerWidth > this.basic_rwd ? Number(params.$selector.getAttribute('swiper-num')) || 1 : 1);
|
245
|
+
|
246
|
+
if (params.$swiper.querySelectorAll('.swiper-slide').length <= gate()) {
|
247
|
+
$swiperSet.navigation = false;
|
248
|
+
$swiperSet.pagination = false;
|
249
|
+
$swiperSet.autoplay = false;
|
250
|
+
$swiperSet.loop = false;
|
251
|
+
|
252
|
+
params.$selector.querySelector('.swiper-button-cover').style.display = 'none';
|
253
|
+
params.$selector.querySelector('.swiper-pagination').style.display = 'none';
|
254
|
+
|
255
|
+
params.$swiper.classList.add('swiper-no-swiping');
|
256
|
+
}
|
257
|
+
|
258
|
+
const $swiper = new SwiperV8(params.$swiper, $swiperSet);
|
259
|
+
|
260
|
+
element.article.swiperList = [];
|
261
|
+
element.article.swiperList.push($swiper);
|
262
|
+
|
263
|
+
return this;
|
264
|
+
}
|
265
|
+
update() {
|
266
|
+
const { elements } = this;
|
267
|
+
|
268
|
+
elements.forEach(parent => {
|
269
|
+
parent.querySelectorAll('._article').forEach(el => {
|
270
|
+
el.article = {};
|
271
|
+
el.article.parent = parent;
|
272
|
+
el.article.params = this.#getArticleData(el);
|
273
|
+
|
274
|
+
this.#createVideo4(el);
|
275
|
+
});
|
276
|
+
});
|
277
|
+
}
|
278
|
+
}
|
279
|
+
|
280
|
+
export default Article4;
|
@@ -0,0 +1 @@
|
|
1
|
+
段落編輯器的 sass 檔案已移動至 WDD_Template
|
@@ -0,0 +1,33 @@
|
|
1
|
+
.category-slider
|
2
|
+
position: relative
|
3
|
+
display: inline-block
|
4
|
+
max-width: 100%
|
5
|
+
overflow: hidden
|
6
|
+
&.slidable
|
7
|
+
mask-image: linear-gradient(270deg, rgba(#fff, 0), #fff 20%, #fff 80%,rgba(#fff, 0))
|
8
|
+
.wrapper
|
9
|
+
cursor: grab
|
10
|
+
&.dragging
|
11
|
+
cursor: grabbing
|
12
|
+
&.moving
|
13
|
+
.category
|
14
|
+
pointer-events: none
|
15
|
+
&.is-start
|
16
|
+
mask-image: linear-gradient(270deg, rgba(#fff, 0), #fff 20%, #fff)
|
17
|
+
&.is-end
|
18
|
+
mask-image: linear-gradient(90deg, rgba(#fff, 0), #fff 20%, #fff)
|
19
|
+
.wrapper
|
20
|
+
position: relative
|
21
|
+
display: flex
|
22
|
+
flex-wrap: nowrap
|
23
|
+
justify-content: flex-start
|
24
|
+
width: 100%
|
25
|
+
height: 100%
|
26
|
+
transform: translate3d(0px, 0, 0)
|
27
|
+
transition-property: transform
|
28
|
+
user-select: none
|
29
|
+
.item
|
30
|
+
flex-shrink: 0
|
31
|
+
&.active
|
32
|
+
a
|
33
|
+
color: red
|