1 Star 2 Fork 0

tommyrunner/vue-share-element

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
VueShareElement.vue 5.54 KB
一键复制 编辑 原始数据 按行查看 历史
<template>
<div class="vue-share-element" ref="elPraRef" @click="getShareElement">
<slot></slot>
</div>
</template>
<script lang="ts" setup>
import { onBeforeUnmount, onMounted, ref } from "vue";
import { setElementStyle } from "./uitls";
import type { WindowType, AttributesType, HooksType } from "./types.d";
// Action Element
interface PropsType {
delay?: number;
zIndex?: number;
}
interface EmitType {
(event: "toPage", el: HTMLElement): void;
}
const elPraRef = ref();
let $window: WindowType = window;
const props = withDefaults(defineProps<PropsType>(), {
delay: 0.62,
zIndex: 2001,
});
const $emit = defineEmits<EmitType>();
let $shareElement: HTMLElement | null = null;
// hooks
let _$hooks: HooksType = {
onEnd: () => {},
onStart: () => {},
};
const CLONE_ID = "_$shareElement";
onBeforeUnmount(() => {
let els = elPraRef.value.children;
if (els && els.length > 0) {
// By default,first element is selected the shared element and deeply cloned
let el = $shareElement || els[0];
let cloneElement: HTMLElement = el.cloneNode(true);
// Get element screen information
let boundingData = el.getBoundingClientRect();
// mark as shareing state(set share element id)
cloneElement.id = CLONE_ID;
// initialize share element styles
setElementStyle(cloneElement, {
position: "fixed",
overflow: "hidden",
margin: "0px",
zIndex: props.zIndex,
top: `${boundingData.top}px`,
left: `${boundingData.left}px`,
width: `${boundingData.width}px`,
height: `${boundingData.height}px`,
transition: `${props.delay}s`,
});
// When then number is greater than 1 record parent container scroll
if (els.length > 1) {
$window._$scrollTop = elPraRef.value.scrollTop;
$window._$scrollLeft = elPraRef.value.scrollLeft;
}
// Record the elements that need to be shared first
$window._$clone = cloneElement;
}
});
onMounted(() => {
// Mark clone elements to prevent duplicate animations on the current page
if ($window._$flag === $window.location.href) {
return;
}
$window._$flag = $window.location.href;
// Created only when there is a real shareElement element present
const cloneElement = $window._$clone;
if (cloneElement) {
document.body.append(cloneElement);
}
// judge the current state(get shre element id)
let _$shareDoc = document.getElementById(CLONE_ID);
if (_$shareDoc) {
// shareing and get children element
let els: Array<HTMLElement> = Array.from(elPraRef.value.children);
if (els && els.length > 0) {
// Judge the many to one situation: find the share record dom
if (els.length > 1) {
let findShareElement = els.find((e: HTMLElement) => {
let attributes: AttributesType = e.attributes;
return $window._$share && attributes.share && attributes.share.value === $window._$share;
});
if (findShareElement) $shareElement = findShareElement;
// Clear the last record after searching the record
$window._$share = undefined;
}
let el: HTMLElement = $shareElement || els[0];
let boundingData = el.getBoundingClientRect();
setElementStyle(el, {
opacity: 0,
});
// perform share actions
console.log($window._$scrollLeft, boundingData.left, els.length);
setElementStyle(_$shareDoc, {
opacity: 1,
top: `${els.length > 1 && $window._$scrollTop ? boundingData.top - $window._$scrollTop : boundingData.top}px`,
left: `${els.length > 1 && $window._$scrollLeft ? boundingData.left - $window._$scrollLeft : boundingData.left}px`,
width: `${boundingData.width}px`,
height: `${boundingData.height}px`,
});
// Set to return recorded scroll
elPraRef.value.scrollTop = $window._$scrollTop;
// Asynchronous handling of rolling over issues
setTimeout(() => {
elPraRef.value.scrollBy({
top: $window._$scrollTop,
left: $window._$scrollLeft,
behavior: "smooth",
});
});
// clear
let domTimeId = setTimeout(() => {
if (_$shareDoc) {
setElementStyle(_$shareDoc, {
opacity: 0,
});
setElementStyle(el, {
opacity: 1,
});
_$shareDoc.remove();
}
// call hook share end
_$hooks.onEnd && _$hooks.onEnd();
clearTimeout(domTimeId);
}, props.delay * 1000);
}
} else {
// Delete elements that have already been created
console.warn("VueShareElement:Receiver not found!");
}
});
function getShareElement(e: MouseEvent) {
let el = e.target as HTMLElement;
if (el) {
$shareElement = el;
// In the case of many to one: record the element triggered last time
let elPra: HTMLElement | null | ParentNode = el;
while (elPra !== null && elPra.parentNode !== elPraRef.value) {
elPra = elPra.parentNode;
}
/**
* Obtain the share attribute in the top-level sub element by clicking on the element
* (Solve the problem that nested subcomponents can not get share attributes)
*/
let attributes: AttributesType = (elPra as HTMLElement).attributes;
if (!$window._$share && attributes && attributes.share) {
$window._$share = attributes.share.value;
}
}
// Because the click event is proxied, the parameter needs to be thrown
$emit("toPage", el);
}
/**
* life cycle
* @param end Called after sharing animation ends
*/
function setHooks(end: Function) {
_$hooks.onEnd = end;
}
// Throw hooks
defineExpose({
setHooks,
});
</script>
<style lang="scss" scoped></style>
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/tommyrunner/vue-share-element.git
git@gitee.com:tommyrunner/vue-share-element.git
tommyrunner
vue-share-element
vue-share-element
master

搜索帮助