# ZeenOverMini
Компонент плеер
# Примеры:
Размеры:
overMini
zeen-over-width
zeen-over-mini-width
zeen-over-button-size
По умолчанию наследуется от zeen-over-icon-size
zeen-over-button-rigth
zeen-over-button-left
zeen-over-icon-size
zeen-over-icon-border-radius
zeen-over-icon-bottom
zeen-over-icon-left
Цвета:
zeen-over-background
По умолчанию наследуется от main-color
Принимает в себя slot,
:isActive="false", мини компонент не активен
:isActive="true", мини компонент активен
:drag="true", можно перетаскивать мини компонент
Пролистайте компонент и мини компонент появится в нижнем левом углу
# props
Название | Тип | Обязательный | По умолчанию | Описание |
---|---|---|---|---|
isActive | Boolean | - | true | активный свернутый элемент или нет |
drag | Boolean | - | true | можно ли перемещать компонент в свернутом виде |
margin | Number | - | 15 | границы от рамки для перемещения компонента |
aspectRatio | String | - | 16:9 | Соотношение сторон компонента в свернутом виде (допустимые значения: 16:9, 4:3, 1:1) |
# Source Code - исходный код компонента
<template>
<div>
<div class="zeen-over" ref="zeenOver">
<slot></slot>
</div>
<div
class="zeen-over__mini"
:class="{
'zeen-over__mini_aspect_ratio_4_3': aspectRatio === '4:3',
'zeen-over__mini_aspect_ratio_1_1': aspectRatio === '1:1',
}"
:style="{
'--zeen-over-mini-bottom': margin + 'px',
'--zeen-over-mini-left': margin + 'px',
}"
v-show="mini"
@mousedown="move($event)"
data-zeen-over="mini"
>
<ZeenActionIcon
:class="[
'zeen-over__button',
{
'zeen-over__button_left': buttonLeft,
},
]"
@click.stop="toIcon"
size="big"
>
<svg width="26" height="14" viewBox="0 0 26 14" xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M0.292893 0.292893C0.683417 -0.0976311
1.31658 -0.0976311 1.70711 0.292893L13
11.5858L24.2929 0.292893C24.6834 -0.0976311
25.3166 -0.0976311 25.7071 0.292893C26.0976
0.683417 26.0976 1.31658 25.7071 1.70711L13.7071
13.7071C13.3166 14.0976 12.6834 14.0976 12.2929
13.7071L0.292893 1.70711C-0.0976311 1.31658
-0.0976311 0.683417 0.292893 0.292893Z"
/>
</svg>
</ZeenActionIcon>
<div class="zeen-over__slot" style="pointer-events: none">
<slot></slot>
</div>
</div>
<div class="zeen-over__icon" v-show="icon" @click="toIcon"></div>
</div>
</template>
<script>
import ZeenActionIcon from '../ZeenActionIcon/ZeenActionIcon'
export default {
name: 'ZeenOverMini',
props: {
isActive: {
type: Boolean,
default: true,
},
drag: {
type: Boolean,
default: true,
},
margin: {
type: Number,
default: 15,
},
aspectRatio: {
type: String,
default: '16:9',
validator: (ratio) => ['16:9', '4:3', '1:1'].includes(ratio),
},
},
components: {ZeenActionIcon},
data() {
return {
mini: false,
icon: false,
observer: null,
buttonLeft: false,
}
},
mounted() {
if (this.isActive) {
this.observerFunc()
}
},
destroyed() {
delete this.observerFunc
delete this.observer
},
methods: {
observerFunc() {
const observerOptions = {
root: null,
rootMargin: '0% 0% 1000% 0%',
threshold: 0,
}
const observerCall = (entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) {
this.mini = true
this.icon = false
} else if (entry.isIntersecting) {
this.mini = false
this.icon = false
}
})
}
this.observer = new IntersectionObserver(observerCall, observerOptions)
this.observer.observe(this.$refs.zeenOver)
},
toIcon() {
if (!this.icon) {
this.icon = true
this.mini = false
} else {
this.icon = false
this.mini = true
}
},
move(event) {
if (this.drag) {
const target = event.target
const offsetX = event.offsetX
const offsetY = event.offsetY
const coords = target.getBoundingClientRect()
const maxHorizontal = document.documentElement.clientWidth - coords.width - this.margin
const maxVertical = document.documentElement.clientHeight - coords.height - this.margin
const iconWidth = target.children[0]?.clientWidth
let deltaX
let deltaY
document.onmousemove = (e) => {
if (target.dataset.zeenOver === 'mini') {
deltaX = e.clientX - offsetX
deltaY = e.clientY - offsetY
if (deltaX >= this.margin && deltaX <= maxHorizontal) {
target.style.left = deltaX + 'px'
}
if (deltaY >= this.margin && deltaY <= maxVertical) {
target.style.top = deltaY + 'px'
target.style.bottom = 'auto'
}
if (deltaX >= maxHorizontal - iconWidth) {
this.buttonLeft = true
} else {
this.buttonLeft = false
}
}
}
document.onmouseup = () => {
document.onmousemove = null
document.onmouseup = null
}
}
},
},
}
</script>
<style lang="scss">
:root {
/* Размеры */
--zeen-over-width: 100%;
--zeen-over-icon-size: 20px;
--zeen-over-icon-border-radius: 4px;
--zeen-over-button-size: var(--zeen-over-icon-size);
--zeen-over-mini-width: 350px;
/* Позиция */
--zeen-over-icon-bottom: 30px;
--zeen-over-icon-left: 30px;
--zeen-over-button-rigth: -50px;
--zeen-over-button-left: -50px;
/* Цвета */
--zeen-over-background: var(--main-color);
}
</style>
<style lang="scss" scoped>
.zeen-over {
display: flex;
width: var(--zeen-over-width);
background: var(--zeen-over-background);
&__icon {
width: var(--zeen-over-icon-size);
height: var(--zeen-over-icon-size);
position: fixed;
top: auto;
bottom: var(--zeen-over-icon-bottom);
left: var(--zeen-over-icon-left);
z-index: 1000;
background: var(--zeen-over-background);
border-radius: var(--zeen-over-icon-border-radius);
cursor: pointer;
}
&::after {
content: '';
display: block;
width: 100%;
padding-top: 56.25%;
}
&__mini {
display: flex;
background: var(--zeen-over-background);
width: var(--zeen-over-mini-width);
position: fixed;
bottom: var(--zeen-over-mini-bottom);
left: var(--zeen-over-mini-left);
z-index: 1000;
&::after {
content: '';
padding-top: 56.25%;
}
&_aspect_ratio_4_3 {
&::after {
padding-top: 75%;
}
}
&_aspect_ratio_1_1 {
&::after {
padding-top: 100%;
}
}
}
&__slot {
display: flex;
width: 100%;
}
&__button {
position: absolute;
top: 0;
right: var(--zeen-over-button-rigth);
&_left {
left: var(--zeen-over-button-left);
}
}
}
</style>