亚伦影音工作室 发表于 2025-5-31 17:17

马氏HTML编辑器

本帖最后由 亚伦影音工作室 于 2025-5-31 17:17 编辑 <br /><br /><style>
        iframe { position: relative; width: 100%; height: 100%; border: none; outline: none; box-sizing: border-box; margin: 0; }
        .wrap{ left:calc(50% - 81px); transform:translateX(-50%);width:1400px; height:700px; background:linear-gradient(to right,#eee 59px,#aaa 60px,#fff 0); border:1px solid gray; border-radius:4px; box-shadow:2px 2px 6px gray; z-index: 1; position:relative; margin: 30px 0; }
        @media screen and (max-width: 1280px) {        .wrap { width: 90vw; height: 75vh; font-size: 12px; } }
        .wrap:hover{ border-color: black; }
        .wrap:has(#editor:focus) { border-width:2px; }
        .same{ position: absolute; top:10px; box-sizing: border-box; padding: 8px; border:none; border-radius: inherit; white-space: pre-wrap; word-break: break-all; font: normal 16px/24px Consolas,'Courier New','Andale Mono',monospace; tab-size: 4; overflow: auto; }
        #editor{ right: 0; width: calc(100% - 60px); height: calc(100% - 20px); resize: none; outline: none; background: #fefefe; scroll-padding: 8px;}
        #line-number{ position: absolute; width: 100%; height: calc(100% - 20px); color: gray; user-select: none; }
        #line-number > span{cursor:pointer;}
        #line-number > span:hover{ font-weight: bold; color: red; }
        #mnbox{ min-height: 0; visibility: hidden; }
        #showBox { position: fixed; top: 0; right: 0; bottom: 0; left: 0; background: #fff; display: none; padding: 0; overflow: hidden; z-index: 10000; margin: 0; }
        #showBox::after { position: absolute; content: '关闭预览'; bottom: 10px; left: calc(50% - 40px); padding: 0 4px; width: 80px; height: 30px; line-height: 30px; text-align: center; border: 1px solid #efe; border-radius: 6px; background: #eee; font-size: 14px; box-shadow: 2px 2px 6px rgba(0,0,0,.25); cursor: pointer; }
        #btnPrev { padding: 2px 8px; cursor: pointer; border: 1px solid #efe; border-radius: 4px; box-shadow:2px 2px 6px rgba(0,0,0,.25); font-size: 14px; }
        #btnPrev:hover { color: red; }
</style>

<h2>Web代码简易编辑器</h2>
<div class="wrap">
        <div id="mnbox" class="same"></div>
        <div id="line-number" class="same"></div>
        <textarea id="editor" class="same" placeholder="输入CSS+HTML+JS代码..."></textarea>
</div>
<p><button type="button" id="btnPrev" title="预览效果">运行代码</button></p>
<div id="showBox" title="点击关闭"></div>

<script>
let isSyncing = false;

const lnum = document.getElementById('line-number');
const editor = document.getElementById('editor');
const mnbox = document.getElementById('mnbox');
const btnPrev = document.getElementById('btnPrev');

const selectLine = (num) => {
        let mpos, tstr = '';
        let ar = editor.value.split('\n');
        for (j = 0; j < num; j ++) {
                tstr += ar + 2;
        }
        mpos = tstr.length;
        editor.setSelectionRange(mpos, mpos + ar.length);
        editor.focus();
};

const addLineNum = () => {
        const lines = editor.value.split('\n');
        let str = '';
        lines.forEach((line, key) => {
                let br = '<br>'.repeat(calcSolftLines(line) || 1);
                let idx = (key + 1).toString().padStart(4,' ');
                str += `<span onclick="selectLine(${key})">${idx}</span>${br}`;
        });
        lnum.innerHTML = str;
};

const calcSolftLines = (text) => {
        const cssdata = window.getComputedStyle(editor);
        mnbox.style.width = editor.offsetWidth + 'px';
        mnbox.style.overflowY = editor.scrollTop > 0 ? 'scroll' : 'hidden';
        mnbox.innerText = text;
        const lineheight = parseFloat(cssdata.getPropertyValue('line-height'));
        const padding = parseFloat(cssdata.getPropertyValue('padding'));
        return Math.floor((mnbox.offsetHeight - padding * 2) / lineheight);
};

const getCurrentLineIndent = () => {
        const cursorPos = editor.selectionStart;
        const content = editor.value;
        let lineStart = content.lastIndexOf('\n', cursorPos - 1) + 1;
        const line = content.slice(lineStart, cursorPos);
        return line.match(/^[\t ]*/)?. || '';
};

const insertTextAtCursor = (text) => {
        const start = editor.selectionStart;
        const end = editor.selectionEnd;
        const content = editor.value;
        editor.value = content.slice(0, start) + text + content.slice(end);
        editor.selectionStart = editor.selectionEnd = start + text.length;
};

const preView = (htmlCode, targetBox) => {
        if (targetBox.innerHTML) return;
console.log('Yes');
        window.localStorage.setItem('ed1', htmlCode);
        const iframe = document.createElement('iframe');
        htmlCode = htmlCode + '\n<style>body {margin: 0; }</style>\n';
        iframe.srcdoc = htmlCode;
        targetBox.appendChild(iframe);
        targetBox.style.display = 'block';
        targetBox.onclick = () => {
                targetBox.innerHTML = '';
            targetBox.style.display = 'none';
        }
};

btnPrev.onclick = () => preView(editor.value, showBox);

editor.onkeydown = (e) => {
        if (e.key === 'Tab') {
                e.preventDefault();
                insertTextAtCursor('\t');
        }
        if (e.key === 'Enter') {
                e.preventDefault();
                const indent = getCurrentLineIndent();
                insertTextAtCursor('\n' + indent);
                addLineNum();
        }
};

const bindEventLnum = () => {
    removeEventEditor();
    lnum.addEventListener('scroll', lnumScroll);
};

const bindEventEditor = () => {
    removeEventLnum();
    editor.addEventListener('scroll', editorScroll);
};

const lnumScroll = () => {
    if (!isSyncing) {
      isSyncing = true;
      editor.scrollTop = lnum.scrollTop;
      isSyncing = false;
    }
};

const editorScroll = () => {
    if (!isSyncing) {
      isSyncing = true;
      lnum.scrollTop = editor.scrollTop;
      isSyncing = false;
    }
};

lnum.addEventListener('mouseover', bindEventLnum);
editor.addEventListener('mouseover', bindEventEditor);
lnum.addEventListener('touchstart', bindEventLnum, { passive: false });
editor.addEventListener('touchstart', bindEventEditor, { passive: false });

const removeEventLnum = () => lnum.removeEventListener('scroll', lnumScroll);
const removeEventEditor = () => editor.removeEventListener('scroll', editorScroll);

editor.oninput = () => addLineNum();
window.onresize = () => addLineNum();
editor.onmouseenter = () => editor.focus();
editor.value = window.localStorage.getItem('ed1');
editor.setSelectionRange(0, 0);
addLineNum();
</script>

杨帆 发表于 2025-5-31 17:49

好,用起来很方便{:4_191:}

亚伦影音工作室 发表于 2025-5-31 19:33

儿童节快乐

本帖最后由 亚伦影音工作室 于 2025-5-31 20:00 编辑 <br /><br /><style>

    #papa { margin: 0 0 0 calc(50% - 718px); width: 1300px; height:720px; background: #000080; overflow: hidden; display: grid; place-items: center; box-shadow: 0px 0px 0px gray; position: relative; z-index: 1; --state: paused; }

#dh{ width: 100%; height: 100%; position: absolute;

z-index: 1;background:url(https://pic1.imgdb.cn/item/683ae68458cb8da5c81eb3bd.jpg)no-repeat center/cover;

top:0px; left:0px;

animation: rod 4s linear infinite var(--state);}

@keyframes rod{0% {opacity: 1;filter:hue-rotate(10deg)}

50% {opacity: 0.3;}100% {opacity: 1;}

}

li-zi { position: absolute; width: 220px; height: 1px; border-radius: 100% 20%;background: tan;animation: imov 2s infinite;z-index: 2;}
@keyframes moving {
to{ opacity: 1; transform: translate(var(--x0),var(--y0)) rotate(var(--deg)); filter:hue-rotate(360deg);}
from{ opacity: 0; transform: translate(0,0) rotate(var(--deg)); }
}
@keyframes rotating { to { transform: rotate(360deg); } }
.mplayer { position: absolute; width: 300px; height: fit-content; display: flex; flex-direction: column; align-items: center; gap: 10px; color: #000; margin: auto; top: 90%; left:64%;z-index: 20; }
    .mplayer::before { position: absolute; content: attr(data-time); width: 100%; text-align-last: justify; pointer-events: none;color: #000; }
    .btnPlay { width: 20px; height: 20px; cursor: pointer; position: relative; }
    .btnPlay::after { position: absolute; content: ''; width: 100%; height: 100%; background: red; clip-path: var(--clip); }
    .progress { --prg: 0%; position: relative; width: 100%; height: 20px; display: grid; place-items: center start; background: linear-gradient(90deg, red var(--prg), gray var(--prg), gray 0) no-repeat center/100% 2px; padding: 0; margin: 0; }
    .thumb { position: absolute; left: calc(var(--prg) - 10px); width: 10px; height: 10px; background: red; border: 1px solid #FF0000; border-radius: 50%; cursor: pointer; box-sizing: border-box; }
    .play { --clip: polygon(10% 0,100% 50%,10% 100%); }
    .pause { --clip: polygon(35% 0,15% 0,15% 100%, 35% 100%,35% 0,75% 0,75% 100%,55% 100%,55% 0); }

.lrc {position:absolute;width: 600px;
    height: 450px;z-index: 3; left:2%;
   border: 0px solid white;
    overflow: hidden;margin: 6px;
}

.lrc #ul {width: 100%;
padding: 0;list-style: none;transition: 0.3s all ease;
    margin: 0}
.lrc #ul li {
font: normal 22px 'FZYaoti', sans-serif;
    color: #000;
    font-weight: normal;
    transition: .3s all ease;
    list-style-type: none;
    text-align: center;display: block;
    width: 100%;
    margin: 0 auto;
    height: 50px;
    line-height: 35px;
}
.lrc #ulli.active{   font-size: 38px;
    color: #ff0000;
text-align: center; }
#fullscreen {border-radius: 4px;position: absolute;background:#0000 ;
color:#fff;box-shadow:0px 0px 0px 1px #fff;z-index: 20;
padding: 4px 10px;
font-size: 12px;
border: none;
cursor: pointer;margin: 8px 5px;left: 85%;top: 4%;
}   
</style>
<div id="papa">
<span id="fullscreen" title="屏展模式">全屏欣赏</span>
<div id="dh" ></div>
    <div class="mplayer" data-time="00:00 00:00">
        <div class="btnPlay play"></div>
        <div class="progress">
                <div class="thumb"></div>
        </div>
</div>
<div class="lrc">
      <ul id="ul">
      </ul>
    </div>

    <audio id="audio"autoplay loop>
            <source src="https://s2.ananas.chaoxing.com/sv-w8/audio/00/44/a9/8ccdc45a29f198c0de7b0878cdc254ce/audio.mp3" type="audio/mpeg">
         </audio>

</div>
<script>
//获取需要操作的元素标识
const mplayer = document.querySelector('.mplayer');
const btnPlay = document.querySelector('.btnPlay');
const progress = document.querySelector('.progress');
const thumb = document.querySelector('.thumb');
const audio = document.querySelector('audio');
// 拖曳操作状态(初始值为假)
let isDraggable = false;

//时间格式化工具函数 :秒转分秒 mm:ss 格式
const formatTime = (seconds) => {
        const mins = Math.floor(seconds / 60);
        const secs = Math.floor(seconds % 60);
        return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
};

// 联动函数 mState :处理按钮形状
const mState = () => {
        btnPlay.className = `btnPlay ${['pause', 'play'][+audio.paused]}`;
};

// 获取设备指针所在点在进度条上的距离(百分比)
const getPercent = (e) => {
        const rect = progress.getBoundingClientRect();
        const left = rect.left;
        const width = rect.width;
        let x = e.clientX ?? e.touches?.?.clientX ?? e.changedTouches?.?.clientX;
        x = Math.min(width, Math.max(0, x - left));
        return x / width * 100;
};

// 滑块鼠标按下、触屏设备手指或触笔按下
thumb.onmousedown = thumb.ontouchstart = (e) => {
        isDraggable = true; // 拖曳状态进行中
        e.preventDefault(); // 阻止默认行为
};

// 文档指针松开、触屏设备手指或触笔弹开
document.onmouseup = document.ontouchend = (e) => {
    // 松开时若拖曳状态为真,驱动 audio 改变播放进度
        if (isDraggable) audio.currentTime = `${getPercent(e) * audio.duration / 100}`;
        isDraggable = false; //然后拖曳状态为假
};

// 文档上指针或手指、触笔移动时
document.onmousemove = document.ontouchmove = (e) => {
        if (!isDraggable) return; // 若不是拖曳状态则忽略之
        // 反之,若处于拖曳状态,给CSS变量 --prg 赋值
        progress.style.setProperty('--prg', `${getPercent(e)}%`);
        // 给时间文本信息即mplayer伪元素 attr(data-time) 函数赋值
        mplayer.dataset.time = `${formatTime(audio.duration * getPercent(e) / 100)} ${formatTime(audio.duration)}`;
};

// 进度条点击事件
progress.onclick = (e) => audio.currentTime = `${getPercent(e) * audio.duration / 100}`;

// 音频标签开始播放和暂停时执行联动函数
audio.onplaying = audio.onpause = () => mState();

// 音频时间更新事件 :驱动文本时间信息及进度条进度变更
audio.ontimeupdate = () => {
        if (isDraggable) return; // 拖曳操作发生时忽略
        mplayer.dataset.time = `${formatTime(audio.currentTime)} ${formatTime(audio.duration)}`;
        progress.style.setProperty('--prg', `${audio.currentTime / audio.duration * 100}%`);
};

// 按钮单击 :播放、暂停状态切换
btnPlay.onclick = () => audio.paused ? audio.play() : audio.pause();

let fs = true;
      fullscreen.onclick = () => {
            if (fs) {
                fullscreen.innerText = '退出全屏';
                papa.requestFullscreen();
            } else {
                fullscreen.innerText = '全屏欣赏';
                document.exitFullscreen();
            }
            fs = !fs;
      };
</script>
<script>
var lrc = `隐形的翅膀 - 左溢&张韶涵
X:每一次
都在徘徊孤单中坚强
每一次
就算很受伤
也不闪泪光
我知道
我一直有双隐形的翅膀
带我飞
给我希望
张:不去想
他们拥有美丽的太阳
我看见
每天的夕阳
也会有变化
我知道
我一直有双隐形的翅膀
带我飞
给我希望
合:我终于
看到
所有梦想都开花
追逐的年轻
歌声多嘹亮
我终于
翱翔
用心凝望不害怕
哪里会有风
就飞多远吧
不去想
他们拥有美丽的太阳
我看见
每天的夕阳
也会有变化
我知道
我一直有双隐形的翅膀
带我飞
给我希望
X:我终于
看到
所有梦想都开花
追逐的年轻
歌声多嘹亮
张:我终于
翱翔
用心凝望不害怕
哪里会有风
就飞多远吧
合:隐形的翅膀
让梦恒久比天长
留一个 愿望
让自己想象
亚伦影音工作室
`;

// 最开始获取到的歌词列表是字符串类型(不好操作)
let lrcArr = lrc.split('\n');
// 接收修正后的歌词数组
let result = [];
// 获取所要用到的dom列表
doms = {
    audio: document.querySelector("#audio"),
    ul: document.querySelector("#ul"),
    container: document.querySelector(".lrc")
}
// 将歌词数组转成由对象组成的数组,对象有time和word两个属性(为了方便操作)
for (let i = 0; i < lrcArr.length; i++) {
    var lrcData = lrcArr.split(']');
    var lrcTime = lrcData.substring(1);
    var obj = {
      time: parseTime(lrcTime),
      word: lrcData
    }
    result.push(obj);
}
// 将tiem转换为秒的形式
function parseTime(lrcTime) {
    lrcTimeArr = lrcTime.split(":")
    return +lrcTimeArr * 60 + +lrcTimeArr;
}
// 获取当前播放到的歌词的下标
function getIndex() {
    let Time = doms.audio.currentTime;
    for (let i = 0; i < result.length; i++) {
      if (result.time > Time) {
            return i - 1;
      }
    }
}
// 创建歌词列表
function createElements() {
    let frag = document.createDocumentFragment(); // 文档片段
    for (let i = 0; i < result.length; i++) {
      let li = document.createElement("li");
      li.innerText = result.word;
      frag.appendChild(li);
    }
    doms.ul.appendChild(frag);
}
createElements();
// 获取显示窗口的可视高度
let containerHeight = doms.container.clientHeight;
// 获取歌词列表的可视高度
let liHeight = doms.ul.children.clientHeight;
// 设置最大最小偏移量,防止显示效果不佳
let minOffset = 0;
let maxOffset = doms.ul.clientHeight - containerHeight;
// 控制歌词滚动移动的函数
function setOffset() {
    let index = getIndex();
    // 计算滚动距离
    let offset = liHeight * index - containerHeight / 2 + liHeight / 2;
    if (offset < minOffset) {
      offset = minOffset;
    };
    if (offset > maxOffset) {
      offset = maxOffset;
    };
    // 滚动
    doms.ul.style.transform = `translateY(-${offset}px)`;
    // 清除之前的active
    let li = doms.ul.querySelector(".active")
    if (li) {
      li.classList.remove("active");
    }
    // 为当前所唱到的歌词添加active
    li = doms.ul.children;
    if (li) {
      li.classList.add("active");
    }
};
// 当audio的播放时间更新时,触发该事件
doms.audio.addEventListener("timeupdate", setOffset);
</script>

<script>



(function() {



let all = 160;

for(let i = 0; i < all; i++) {

    let movBall = document.createElement('li-zi');

    let hudu = Math.PI / 180 * 360 / all * i;

    let xx = 800 * Math.cos(hudu), yy = 800 * Math.sin(hudu);

    movBall.style.cssText += `

      --x0: ${xx}px;

      --y0: ${yy}px;

      --deg: ${360 / all * i}deg;

      background: #${Math.random().toString(16).substr(-6)};

      animation: moving ${Math.random() * 2 + 2}s -${Math.random() * 2}s infinite var(--state);

    `;

    papa.prepend(movBall);

}
let mState = () => papa.style.setProperty('--state', audio.paused ? 'paused' : 'running');

audio.addEventListener('playing',mState,false);

audio.addEventListener('pause',mState,false);
})();

</script>

杨帆 发表于 2025-6-1 11:28

亚伦影音工作室 发表于 2025-5-31 19:33
本帖最后由 亚伦影音工作室 于 2025-5-31 20:00 编辑

    #papa { margin: 0 0 0 calc(50% - 718px);...

漂亮!祝亚伦老师童心不泯、青春永驻{:4_191:}

红影 发表于 2025-6-1 23:32

亚伦影音工作室 发表于 2025-5-31 19:33
本帖最后由 亚伦影音工作室 于 2025-5-31 20:00 编辑

    #papa { margin: 0 0 0 calc(50% - 718px);...

谢谢亚伦老师的美好祝福,祝您六一儿童节快乐{:4_187:}
页: [1]
查看完整版本: 马氏HTML编辑器