找到
173
篇与
站长可乐
相关的结果
- 第 3 页
-
发现一个有趣的便签墙网站 发现一个不错的网站,这个网站作者是:https://github.com/uninto/notes,纯html、css、js实现。 有人说这个类似之前的许愿墙,我觉得也可以把这个元素加进去,毕竟我群里很多宅男腐女,最喜欢这个玩意儿了,晚些我直接上线到我的工具箱里 mhgb3msq.png图片 因为这个只有一个前端页面,代码如下,我就准备做个后端出来,到时候重新开个帖子,供大家使用。 <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>便签墙</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background-image: linear-gradient(0deg, #eee 1px, transparent 0), linear-gradient(90deg, #eee 1px, transparent 0); background-size: 30px 30px; color: #333; min-height: 100dvh; overflow: hidden; } body.has-maximized-card { overflow: hidden; } body.is-mobile { overflow-y: auto; } #board { position: relative; width: 100vw; height: 100dvh; overflow: hidden; } body.is-mobile #board { height: auto; min-height: 100dvh; } .card { position: absolute; width: 220px; border-radius: 12px; box-shadow: 0 16px 35px rgba(0, 0, 0, 0.2); background: #fff; border: 1px solid rgba(0, 0, 0, 0.08); overflow: hidden; opacity: 0; transform-origin: center; transition: transform 0.35s ease, opacity 0.35s ease, left 0.35s ease, top 0.35s ease, width 0.35s ease, height 0.35s ease, border-radius 0.35s ease; } .card.dragging { transition: none; box-shadow: 0 22px 45px rgba(0, 0, 0, 0.35); } .card.maximized { position: fixed; inset: 0; width: 100vw; height: 100vh; height: 100dvh; border-radius: 0; box-shadow: 0 28px 60px rgba(0, 0, 0, 0.4); } .card-header { display: flex; align-items: center; justify-content: space-between; padding: 10px 12px; background: rgba(255, 255, 255, 0.7); cursor: grab; user-select: none; touch-action: pan-y; } .card-header.dragging { cursor: grabbing; } .window-controls { display: flex; align-items: center; gap: 6px; } .window-controls .control { position: relative; width: 12px; height: 12px; border-radius: 50%; border: 1px solid rgba(0, 0, 0, 0.08); background: #ccc; cursor: pointer; outline: none; padding: 0; display: inline-flex; align-items: center; justify-content: center; } .window-controls .control.close { background: #ff5f57; border-color: #e0443e; } .window-controls .control.minimize { background: #febb2e; border-color: #dea123; } .window-controls .control.maximize { background: #28c840; border-color: #1aab2c; } .window-controls .control::after { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); opacity: 0; transition: opacity 0.2s ease; } .card-header:hover .window-controls .control::after { opacity: 0.8; } .window-controls .control.close::after { content: '×'; width: auto; height: auto; background: none; font-size: 10px; line-height: 1; font-weight: 700; color: rgba(0, 0, 0, 0.7); } .window-controls .control.minimize::after { width: 6px; height: 2px; background: rgba(0, 0, 0, 0.6); } .window-controls .control.maximize::after { width: 6px; height: 6px; background: linear-gradient( 45deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0.6) 45%, transparent 45%, transparent 55%, rgba(0, 0, 0, 0.6) 55%, rgba(0, 0, 0, 0.6) 100% ); } .card-title { font-size: 13px; font-weight: 600; color: rgba(0, 0, 0, 0.55); padding-left: 10px; flex: 1; } .card-body { padding: 16px; font-size: 16px; line-height: 1.4; font-weight: 600; color: rgba(0, 0, 0, 0.72); word-break: break-word; overflow-wrap: anywhere; white-space: normal; } .card.maximized { display: flex; flex-direction: column; } .card.maximized .card-title { display: none; } .card.maximized .card-body { flex: 1; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; text-align: center; padding: clamp(32px, min(10vw, 10vh), 128px); padding-top: clamp(72px, min(14vw, 14vh), 192px); font-size: clamp(48px, min(18vw, 18vh), 200px); line-height: 1.05; } @media (max-width: 768px) { .card { width: 180px; border-radius: 10px; } .card-body { padding: 14px; font-size: 14px; } .card-title { font-size: 12px; } } </style> </head> <body> <div id="board"></div> <script> const board = document.getElementById('board') const messages = [ '保持好心情', '多喝水哦', '今天辛苦啦', '早点休息', '记得吃水果', '加油,你可以的', '祝你顺利', '保持微笑呀', '愿所有烦恼都消失', '期待下一次见面', '梦想总会实现', '天气冷了,多穿衣服', '记得给自己放松', '每天都要元气满满', '今天也要好好爱自己', '适当休息一下' ] const colors = [ '#ffe0e3', '#c7f0ff', '#ffd8a8', '#d9f2d9', '#e5d7ff', '#f9f7d9', '#d2f0f8', '#ffd4f5' ] const cardStates = new WeakMap() // Reserve a very high层级给全屏卡片,避免被后续元素覆盖 const MAXIMIZED_LAYER = 1000000 let activeMaximizedCard = null const pointerMediaQuery = window.matchMedia('(pointer: coarse)') let isMobile = pointerMediaQuery.matches || window.innerWidth <= 768 let maxCards = isMobile ? 120 : 180 // 限制 DOM 节点数量,减轻移动端压力 const initialCardCount = isMobile ? 18 : 30 let spawnInterval = isMobile ? 700 : 400 let zIndexCursor = 200 let spawnTimer = null document.body.classList.toggle('is-mobile', isMobile) function randomFrom(array) { return array[Math.floor(Math.random() * array.length)] } function clamp(value, min, max) { return Math.min(Math.max(value, min), max) } function applyTransform(card, state) { const scale = state.scale ?? 1 const angle = state.angle ?? 0 card.style.transform = `scale(${scale}) rotate(${angle}deg)` } function bringToFront(card) { if (card === activeMaximizedCard) { card.style.zIndex = MAXIMIZED_LAYER return } zIndexCursor += 1 if (activeMaximizedCard && zIndexCursor >= MAXIMIZED_LAYER) { zIndexCursor = MAXIMIZED_LAYER - 1 } card.style.zIndex = zIndexCursor } function updateBodyMaximizedState() { document.body.classList.toggle( 'has-maximized-card', Boolean(activeMaximizedCard) ) } function scheduleNextSpawn() { clearTimeout(spawnTimer) spawnTimer = setTimeout(() => { if (!document.hidden) { createCard() } scheduleNextSpawn() }, spawnInterval) } function syncMobileMode() { const nextIsMobile = pointerMediaQuery.matches || window.innerWidth <= 768 if (nextIsMobile === isMobile) return isMobile = nextIsMobile maxCards = isMobile ? 120 : 180 spawnInterval = isMobile ? 700 : 400 document.body.classList.toggle('is-mobile', isMobile) scheduleNextSpawn() } function handleBoardClick(event) { const control = event.target.closest('.control') if (!control) return const card = control.closest('.card') if (!card || !board.contains(card)) return event.preventDefault() if (control.classList.contains('close')) { closeCard(card) } else if (control.classList.contains('minimize')) { minimizeCard(card) } else if (control.classList.contains('maximize')) { toggleMaximize(card) } } function handleBoardPointerDown(event) { const card = event.target.closest('.card') if (!card || !board.contains(card)) return const control = event.target.closest('.control') const header = event.target.closest('.card-header') const pointerType = event.pointerType || 'mouse' const isPrimaryPointer = event.isPrimary !== false if ( header && !control && pointerType !== 'touch' && isPrimaryPointer ) { startDrag(event, card) return } bringToFront(card) } function handleBoardDoubleClick(event) { const header = event.target.closest('.card-header') if (!header || event.target.closest('.control')) return const card = header.closest('.card') if (!card || !board.contains(card)) return toggleMaximize(card) } board.addEventListener('click', handleBoardClick) board.addEventListener('pointerdown', handleBoardPointerDown) board.addEventListener('dblclick', handleBoardDoubleClick) function closeCard(card) { const state = cardStates.get(card) if (!state || state.closing) return if (card === activeMaximizedCard) { activeMaximizedCard = null updateBodyMaximizedState() } state.closing = true state.scale = 0.1 card.style.opacity = '0' applyTransform(card, state) const handleTransitionEnd = event => { if (event.propertyName === 'opacity') { card.removeEventListener('transitionend', handleTransitionEnd) card.remove() } } card.addEventListener('transitionend', handleTransitionEnd) } function minimizeCard(card) { const state = cardStates.get(card) if (!state || state.closing) return // 最小化动画:缩小并淡出到底部,结束时移除节点释放内存 const runMinimize = () => { state.closing = true bringToFront(card) const bottom = Math.max(window.innerHeight - 24, 0) const targetLeft = clamp( state.left, 16, Math.max(window.innerWidth - card.offsetWidth - 16, 16) ) state.left = targetLeft state.top = bottom state.scale = 0.1 state.angle = 0 card.style.left = `${targetLeft}px` card.style.top = `${bottom}px` card.style.opacity = '0.35' applyTransform(card, state) const handleTransitionEnd = event => { if (event.propertyName === 'transform') { card.removeEventListener('transitionend', handleTransitionEnd) card.remove() } } card.addEventListener('transitionend', handleTransitionEnd) } if (state.maximized) { restoreFromMaximize(card, state) requestAnimationFrame(() => { requestAnimationFrame(runMinimize) }) return } runMinimize() } function toggleMaximize(card) { const state = cardStates.get(card) if (!state || state.closing) return if (state.maximized) { restoreFromMaximize(card, state) } else { maximizeCard(card, state) } } function maximizeCard(card, state) { if (activeMaximizedCard && activeMaximizedCard !== card) { const activeState = cardStates.get(activeMaximizedCard) if (activeState) { restoreFromMaximize(activeMaximizedCard, activeState) } } state.beforeMaximize = { left: state.left, top: state.top, scale: state.scale ?? 1, angle: state.angle ?? 0, width: card.offsetWidth, height: card.offsetHeight, inlinePosition: card.style.position } card.classList.add('maximized') card.style.position = 'fixed' card.style.left = '0px' card.style.top = '0px' card.style.width = '100vw' card.style.height = '100dvh' card.style.borderRadius = '0' state.left = 0 state.top = 0 state.scale = 1 state.angle = 0 applyTransform(card, state) activeMaximizedCard = card bringToFront(card) state.maximized = true updateBodyMaximizedState() } function restoreFromMaximize(card, state) { const previous = state.beforeMaximize if (!previous) return card.classList.remove('maximized') card.style.position = previous.inlinePosition || 'absolute' card.style.left = `${previous.left}px` card.style.top = `${previous.top}px` card.style.width = `${previous.width}px` card.style.height = `${previous.height}px` card.style.borderRadius = '12px' state.left = previous.left state.top = previous.top state.scale = previous.scale ?? 1 state.angle = previous.angle ?? state.angle ?? 0 applyTransform(card, state) state.maximized = false if (activeMaximizedCard === card) { activeMaximizedCard = null updateBodyMaximizedState() } bringToFront(card) setTimeout(() => { if (!state.maximized) { card.style.width = '' card.style.height = '' card.style.borderRadius = '' if (previous.inlinePosition) { card.style.position = previous.inlinePosition } else { card.style.position = '' } state.beforeMaximize = null } }, 360) } function startDrag(event, card) { const control = event.target.closest('.control') if (control) return const state = cardStates.get(card) if (!state || state.closing || state.maximized) return // 鼠标拖拽使用 rAF 节流,避免频繁触发布局计算 event.preventDefault() bringToFront(card) const header = card.querySelector('.card-header') card.classList.add('dragging') header.classList.add('dragging') state.dragging = true state.dragOffsetX = event.clientX - state.left state.dragOffsetY = event.clientY - state.top let dragFrame = null let pendingLeft = state.left let pendingTop = state.top const commitDrag = () => { dragFrame = null const maxLeft = Math.max(window.innerWidth - card.offsetWidth, 0) const maxTop = Math.max(window.innerHeight - card.offsetHeight, 0) state.left = clamp(pendingLeft, -card.offsetWidth * 0.4, maxLeft) state.top = clamp(pendingTop, -card.offsetHeight * 0.4, maxTop) card.style.left = `${state.left}px` card.style.top = `${state.top}px` } const handlePointerMove = moveEvent => { if (!state.dragging) return pendingLeft = moveEvent.clientX - state.dragOffsetX pendingTop = moveEvent.clientY - state.dragOffsetY if (dragFrame === null) { dragFrame = requestAnimationFrame(commitDrag) } } const handlePointerUp = () => { state.dragging = false card.classList.remove('dragging') header.classList.remove('dragging') if (dragFrame !== null) { cancelAnimationFrame(dragFrame) commitDrag() } document.removeEventListener('pointermove', handlePointerMove) document.removeEventListener('pointerup', handlePointerUp) } document.addEventListener('pointermove', handlePointerMove) document.addEventListener('pointerup', handlePointerUp) } function createCard() { const card = document.createElement('div') card.className = 'card' const color = randomFrom(colors) const angleRange = isMobile ? 6 : 10 const angle = (Math.random() - 0.5) * angleRange const entryScale = isMobile ? 0.8 : 0.65 const cardWidth = isMobile ? 180 : 220 const cardHeight = isMobile ? 130 : 140 const horizontalMargin = isMobile ? 12 : 16 const verticalMargin = isMobile ? 12 : 20 const left = horizontalMargin + Math.random() * Math.max(window.innerWidth - cardWidth - horizontalMargin * 2, 0) const top = verticalMargin + Math.random() * Math.max(window.innerHeight - cardHeight - verticalMargin * 2, 0) card.style.background = color card.style.left = `${left}px` card.style.top = `${top}px` card.style.opacity = '0' if (activeMaximizedCard && zIndexCursor >= MAXIMIZED_LAYER - 2) { zIndexCursor = MAXIMIZED_LAYER - 2 } card.style.zIndex = ++zIndexCursor card.innerHTML = ` <div class="card-header"> <div class="window-controls"> <button class="control close" type="button" aria-label="关闭"></button> <button class="control minimize" type="button" aria-label="最小化"></button> <button class="control maximize" type="button" aria-label="最大化"></button> </div> <div class="card-title">温馨提示</div> </div> <div class="card-body">${randomFrom(messages)}</div> ` const state = { angle, scale: entryScale, left, top, maximized: false, closing: false } cardStates.set(card, state) applyTransform(card, state) board.appendChild(card) requestAnimationFrame(() => { requestAnimationFrame(() => { state.scale = 1 applyTransform(card, state) card.style.opacity = '1' }) }) if (board.children.length > maxCards) { const oldest = board.firstElementChild if (oldest && oldest !== card) { oldest.remove() } } } for (let i = 0; i < initialCardCount; i++) { setTimeout(createCard, i * (isMobile ? 60 : 40)) } scheduleNextSpawn() document.addEventListener('visibilitychange', () => { if (!document.hidden) { scheduleNextSpawn() } }) if (typeof pointerMediaQuery.addEventListener === 'function') { pointerMediaQuery.addEventListener('change', syncMobileMode) } else if (typeof pointerMediaQuery.addListener === 'function') { pointerMediaQuery.addListener(syncMobileMode) } window.addEventListener('resize', syncMobileMode) </script> </body> </html> -
为什么拆卡直播如此流行? 拆卡直播的流行源于多重因素的综合作用,包括心理吸引力、经济激励、社交需求以及行业特性。以下基于相关信息和当前环境(2025年9月)进行专业分析: 心理因素:不确定性带来的刺激和情绪价值 拆卡直播利用人类对不确定性的天然偏好,创造出类似博彩的“以小博大”机制。消费者支付小额费用(如2元、5元或10元每包)参与拆卡,期望抽中稀有卡牌(如限量版或高价值卡片),这能触发多巴胺释放,提供即时快感和成就感。例如,稀有卡在二级市场可能溢价数十倍,强化了“运气致富”的幻想。 情绪价值是关键驱动力:直播间的互动氛围(如主播的夸张话术、观众围观)增强了代入感,让用户感到参与一场集体游戏。青少年群体尤其易受影响,因为这满足了他们在学业压力下的心理缺口(如寻求认同、社交归属),但这也可能导致成瘾行为,扭曲对努力与运气的认知。 经济因素:低门槛入局与潜在高回报 拆卡直播的运营成本极低,仅需基础设备(如桌子、剪刀、卡牌库存),无需主播露脸或复杂技术。这使得大量个体或小团队能快速入局,2023-2024年期间曾被视为“蓝海”生意,头部主播单场销售额可达数万元。 然而,行业已陷入内卷:市场竞争加剧后,直播间通过设置复杂玩法(如“叠叠乐”或“必中包”)吸引用户,但实际利润被价格战侵蚀。主播常人为操控爆率(如预选稀有卡牌,优先分配给高消费用户),制造虚假“欧气”现象,这虽短期提升销量,却破坏了公平性,导致消费者损失(如投入3万元仅获普卡)。截至2025年9月,行业正经历信任危机,批量直播间倒闭,幸存者依赖供应链优势或创新玩法维持。 社会与行业因素:社交需求与监管缺失 拆卡直播构建了虚拟社交圈,用户通过分享抽卡结果或收集成套卡牌获得群体认同,这尤其吸引青少年和二次元文化爱好者。平台算法(如抖音、小红书的热度上升)进一步推高了曝光度,形成“跟风”效应。 但行业监管滞后:主播的诱导行为(如虚假宣传爆率)涉嫌擦边赌博,违反公平交易原则。未成年人保护机制薄弱(如身份验证缺失),导致退费维权困难。当前趋势显示,监管压力正在加大(如要求公示概率、设置消费上限),但乱象仍存,需行业自律和政策完善。 总结与建议 拆卡直播的流行是娱乐消费与人性博弈的结合,其吸引力源于低成本、高刺激和社交属性,但内在风险(如操控爆率、成瘾问题)已引发内卷和信任危机。截至2025年9月,行业热度有所降温,但头部直播间仍能通过创新维持。消费者应理性参与,避免过度投入;监管方需强化规则(如概率透明化),以促进行业健康发展。 -
喜欢网络简报 2025年8月9日 星期六 1. 证监会:将继续严把发行上市入口关,不会出现大规模扩容的情况。 2. 工行、农行、建行等多家银行响应消费贷贴息,贴息标准多在1.5%左右。 3. 嫦娥六号月球样品最新研究成果发布:揭示月球背面月幔超还原状态。 4. 北京优化限购:符合条件家庭购买五环外住房不限套数。 5. 上海推女职工产假社保补贴政策:补贴用人单位50%,8月底可申请。 6. 山东养老服务消费补贴来了:不限户籍,60岁以上中重度失能可申领。 7. 2025世界人形机器人运动会下周启幕,将有280支队伍参赛。 8. 日媒:日本首相石破茂再次表明将继续留任。 9. 柬埔寨首相:已正式提名特朗普获诺贝尔和平奖。 10. 美国称悬赏5000万美元缉拿委内瑞拉总统马杜罗。 11. 以色列已批准占领加沙城计划,拟建立加沙新民事政府。 12.证监会严肃查处贵州辖区深交所主板上市公司*ST高鸿严重财务造假案件,对大唐高鸿罚款1.6亿元。 13.快手上线独立外卖入口,外卖商品二季度支付用户数环比增长超3倍。 【心语】无论遇见何种风景,都请欣然接受。用随遇而安的态度,过顺其自然的生活。