2021-09-26 22:09:33 +00:00
|
|
|
|
<template>
|
|
|
|
|
<div class="lay-code">
|
2021-11-07 07:56:24 +00:00
|
|
|
|
<div id="source" class="source">
|
2021-09-26 22:09:33 +00:00
|
|
|
|
<slot />
|
2021-10-12 03:30:07 +00:00
|
|
|
|
<div v-if="$slots.description" class="description">
|
2021-09-26 22:09:33 +00:00
|
|
|
|
<slot name="description" />
|
|
|
|
|
</div>
|
2022-01-31 23:23:20 +00:00
|
|
|
|
</div>
|
|
|
|
|
<div ref="meta" class="meta">
|
2021-09-26 22:09:33 +00:00
|
|
|
|
<div class="language-html">
|
|
|
|
|
<slot name="code" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2021-11-07 07:56:24 +00:00
|
|
|
|
<div :class="{ 'is-fixed': isFixContorl }" class="control">
|
2022-01-28 22:43:48 +00:00
|
|
|
|
<i class="layui-icon layui-icon-play btn" @click="onPlayground" title="在 Playground 中打开" />
|
|
|
|
|
<i class="layui-icon layui-icon-file btn" @click="copy" title="复制代码" />
|
|
|
|
|
<i class="layui-icon layui-icon-fonts-code btn" @click="toggle" title="查看代码"/>
|
2021-09-26 22:09:33 +00:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
2021-12-12 11:53:33 +00:00
|
|
|
|
import { layer } from '@layui/layer-vue'
|
2021-09-26 22:09:33 +00:00
|
|
|
|
import { onMounted, onUnmounted, ref, watch } from 'vue'
|
|
|
|
|
|
2022-01-28 22:43:48 +00:00
|
|
|
|
import { usePlayGround } from '../plugin/usePlayground'
|
|
|
|
|
|
2021-09-26 22:09:33 +00:00
|
|
|
|
const meta = ref<HTMLElement>({} as HTMLElement)
|
|
|
|
|
const isFixContorl = ref(false)
|
|
|
|
|
const codeAreaHeight = ref(0)
|
|
|
|
|
|
2021-10-12 03:30:07 +00:00
|
|
|
|
const show = ref(false)
|
2021-09-26 22:09:33 +00:00
|
|
|
|
|
2021-10-22 07:37:22 +00:00
|
|
|
|
const toggle = function () {
|
2021-10-12 03:30:07 +00:00
|
|
|
|
show.value = !show.value
|
2021-09-26 22:09:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-28 22:43:48 +00:00
|
|
|
|
const onPlayground = function(){
|
|
|
|
|
const foundCodes = meta.value.getElementsByClassName('language-html')
|
|
|
|
|
const foundCode = foundCodes[0];
|
2022-02-09 03:51:20 +00:00
|
|
|
|
const SourceCode = foundCode.textContent || "";
|
2022-01-28 22:43:48 +00:00
|
|
|
|
|
2022-02-09 03:51:20 +00:00
|
|
|
|
const { link } = usePlayGround(SourceCode, true)
|
2022-01-28 22:43:48 +00:00
|
|
|
|
window.open(link)
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-07 07:55:08 +00:00
|
|
|
|
const copy = function () {
|
2021-12-12 11:53:33 +00:00
|
|
|
|
const foundCodes = meta.value.getElementsByClassName('language-html')
|
2021-12-26 08:34:44 +00:00
|
|
|
|
const foundCode = foundCodes[0];
|
|
|
|
|
let successful = false;
|
|
|
|
|
// 使用原生系统剪贴板,只适用被授权安全的站点,http下不能使用
|
|
|
|
|
if (navigator.clipboard && document.hasFocus()) {
|
|
|
|
|
const text = foundCode.textContent || "";
|
2021-12-12 11:53:33 +00:00
|
|
|
|
navigator.clipboard.writeText(text);
|
2021-12-26 08:34:44 +00:00
|
|
|
|
successful = true;
|
|
|
|
|
} else if (window.getSelection()){
|
|
|
|
|
// 使用document.execCommand
|
|
|
|
|
// 代码div显示状态直接使用,隐藏状态则创建一个div
|
|
|
|
|
var range = document.createRange();
|
|
|
|
|
let copyDiv;
|
|
|
|
|
if (show.value) {
|
|
|
|
|
range.selectNode(foundCode);
|
|
|
|
|
} else {
|
|
|
|
|
copyDiv = document.createElement('div');
|
|
|
|
|
copyDiv.innerHTML = foundCode.innerHTML;
|
|
|
|
|
copyDiv.style.position="fixed";
|
|
|
|
|
copyDiv.style.left="-9999px";
|
|
|
|
|
document.body.appendChild(copyDiv);
|
|
|
|
|
range.selectNode(copyDiv);
|
|
|
|
|
}
|
|
|
|
|
window.getSelection()?.addRange(range);
|
|
|
|
|
try {
|
|
|
|
|
successful = document.execCommand('copy');
|
|
|
|
|
} catch(err) {
|
|
|
|
|
successful = false;
|
|
|
|
|
console.error(err);
|
|
|
|
|
}
|
|
|
|
|
window.getSelection()?.removeAllRanges();
|
|
|
|
|
copyDiv?.remove();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (successful) {
|
2021-12-12 11:53:33 +00:00
|
|
|
|
layer.msg("复制成功", { icon : 1, time: 1000}, ()=>{})
|
|
|
|
|
} else {
|
|
|
|
|
layer.msg("复制失败", { icon : 2, time: 1000}, ()=>{})
|
|
|
|
|
}
|
2021-11-07 07:55:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-26 22:09:33 +00:00
|
|
|
|
onMounted(() => {
|
|
|
|
|
const foundDescs = meta.value.getElementsByClassName('description')
|
|
|
|
|
const foundCodes = meta.value.getElementsByClassName('language-html')
|
|
|
|
|
|
|
|
|
|
if (foundDescs.length) {
|
|
|
|
|
codeAreaHeight.value =
|
|
|
|
|
foundDescs[0].clientHeight + foundCodes[0].clientHeight + 30
|
|
|
|
|
} else {
|
|
|
|
|
codeAreaHeight.value = foundCodes[0].clientHeight + 20
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
window.removeEventListener('scroll', handleScroll)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
watch(show, (value) => {
|
|
|
|
|
if (value) {
|
|
|
|
|
meta.value.style.height = `${codeAreaHeight.value}px`
|
|
|
|
|
window.addEventListener('scroll', handleScroll)
|
|
|
|
|
setTimeout(handleScroll, 100)
|
|
|
|
|
} else {
|
|
|
|
|
meta.value.style.height = '0'
|
|
|
|
|
window.removeEventListener('scroll', handleScroll)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
function handleScroll() {
|
|
|
|
|
const { top, bottom } = meta.value.getBoundingClientRect()
|
|
|
|
|
isFixContorl.value =
|
|
|
|
|
bottom > window.innerHeight && top + 44 <= window.innerHeight
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
.lay-code {
|
|
|
|
|
margin: 1rem 0;
|
|
|
|
|
border: 1px solid whitesmoke;
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
background: var(--c-bg);
|
|
|
|
|
transition: all 0.2s;
|
|
|
|
|
}
|
|
|
|
|
.lay-code:hover {
|
|
|
|
|
box-shadow: var(--shadow-2);
|
|
|
|
|
}
|
|
|
|
|
.lay-code .source {
|
|
|
|
|
padding: 24px;
|
2022-01-31 23:23:20 +00:00
|
|
|
|
padding-bottom:15px;
|
2021-09-26 22:09:33 +00:00
|
|
|
|
}
|
|
|
|
|
.lay-code .meta {
|
|
|
|
|
padding: 0 10px;
|
|
|
|
|
height: 0;
|
|
|
|
|
background-color: var(--c-page-background);
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
transition: height 0.2s;
|
|
|
|
|
}
|
2022-01-31 23:23:20 +00:00
|
|
|
|
.lay-code .source .description {
|
2021-09-26 22:09:33 +00:00
|
|
|
|
padding: 20px;
|
2022-01-31 23:23:20 +00:00
|
|
|
|
margin: 20px 0;
|
|
|
|
|
margin-bottom: 0px;
|
2021-10-07 16:17:34 +00:00
|
|
|
|
border: 1px solid whitesmoke;
|
2021-09-26 22:09:33 +00:00
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
background: var(--c-bg);
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
line-height: 22px;
|
|
|
|
|
color: var(--c-text-light-1);
|
|
|
|
|
word-break: break-word;
|
|
|
|
|
}
|
2022-01-31 23:23:20 +00:00
|
|
|
|
.lay-code .source .description p {
|
2021-09-26 22:09:33 +00:00
|
|
|
|
margin: 0 !important;
|
|
|
|
|
line-height: 26px !important;
|
|
|
|
|
}
|
2022-01-31 23:23:20 +00:00
|
|
|
|
.lay-code .source .description code {
|
2021-09-26 22:09:33 +00:00
|
|
|
|
display: inline-block;
|
|
|
|
|
padding: 1px 5px;
|
|
|
|
|
margin: 0 4px;
|
|
|
|
|
height: 18px;
|
2021-10-07 16:17:34 +00:00
|
|
|
|
border-radius: 2px;
|
2021-09-26 22:09:33 +00:00
|
|
|
|
background-color: var(--code-inline-bg-color);
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
line-height: 18px;
|
|
|
|
|
color: var(--c-text-light);
|
|
|
|
|
}
|
2022-01-31 23:23:20 +00:00
|
|
|
|
|
2021-09-26 22:09:33 +00:00
|
|
|
|
.lay-code .control {
|
|
|
|
|
height: 44px;
|
|
|
|
|
box-sizing: border-box;
|
2021-09-27 01:24:54 +00:00
|
|
|
|
margin-top: 10px;
|
2021-09-26 22:09:33 +00:00
|
|
|
|
border-top: 1px solid whitesmoke;
|
|
|
|
|
border-bottom-left-radius: 4px;
|
|
|
|
|
border-bottom-right-radius: 4px;
|
|
|
|
|
background: var(--c-bg);
|
|
|
|
|
text-align: center;
|
|
|
|
|
color: var(--c-text);
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
width: 100%;
|
|
|
|
|
user-select: none;
|
|
|
|
|
}
|
|
|
|
|
.lay-code .control.is-fixed {
|
|
|
|
|
position: sticky;
|
|
|
|
|
z-index: 11;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
}
|
|
|
|
|
.lay-code .control:hover {
|
|
|
|
|
background-color: var(--c-page-background);
|
|
|
|
|
color: var(--c-brand);
|
|
|
|
|
}
|
|
|
|
|
.lay-code .control > i {
|
|
|
|
|
display: inline-block;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
line-height: 44px;
|
|
|
|
|
transition: all 0.3s;
|
2021-10-22 07:37:22 +00:00
|
|
|
|
padding-left: 10px;
|
|
|
|
|
padding-right: 10px;
|
2021-09-26 22:09:33 +00:00
|
|
|
|
}
|
2022-01-28 22:43:48 +00:00
|
|
|
|
.btn:hover::before {
|
|
|
|
|
color: #5FB878;
|
|
|
|
|
}
|
2021-12-26 08:34:44 +00:00
|
|
|
|
</style>
|