code
vue 拖拽
<template>
<transition-group tag="div" class="container">
<div
class="item"
v-for="(item) in items"
:key="item.key"
:style="{background:item.color,width:'80px',height:'80px',}"
draggable="true"
@dragstart="handleDragStart($event, item)"
@dragover.prevent="handleDragOver($event, item)"
@dragenter="handleDragEnter($event, item)"
@dragend="handleDragEnd($event, item)"
></div>
</transition-group>
</template>
<script>
export default {
name: "Toolbar",
data() {
return {
items: JSON.parse(localStorage.getItem('list')) || [
{ key: 1, color: "red" },
{ key: 2, color: "yellow" },
{ key: 3, color: "green" }
],
dragging: null
};
},
methods: {
handleDragStart(e, item) {
this.dragging = item;
},
handleDragEnd(e, item) {
this.dragging = null;
},
//首先把div变成可以放置的元素,即重写dragenter/dragover
handleDragOver(e) {
e.dataTransfer.dropEffect = "move"; // e.dataTransfer.dropEffect="move";//在dragenter中针对放置目标来设置!
},
handleDragEnter(e, item) {
e.dataTransfer.effectAllowed = "move"; //为需要移动的元素设置dragstart事件
if (item === this.dragging) {
return;
}
const newItems = [...this.items];
console.log(newItems);
const src = newItems.indexOf(this.dragging);
const dst = newItems.indexOf(item);
newItems.splice(dst, 0, ...newItems.splice(src, 1));
this.items = newItems;
localStorage.setItem('list', JSON.stringify(newItems))
}
},
created() {
console.log(localStorage.getItem('list'))
}
};
</script>
<style scoped>
.container {
width: 80px;
height: 300px;
position: absolute;
left: 0;
display: flex;
flex-direction: column;
padding: 0;
}
.item {
margin-top: 10px;
transition: all linear 0.3s;
}
</style>
vue el-dialog 拖拽 directives 指令
<template>
<div>
<el-button type="primary" @click="dialogVisible = true">主要按钮</el-button>
<el-dialog
title="提示"
:visible.sync="dialogVisible"
v-dialogDrag
width="30%"
:close-on-click-modal="false">
<span>这是一段信息</span>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
dialogVisible: false
};
}
};
</script>
// 在 utils 中新建 directives.js 文件
import Vue from 'vue'
// v-dialogDrag: 弹窗拖拽
Vue.directive('dialogDrag', {
bind(el, binding, vnode, oldVnode) {
const dialogHeaderEl = el.querySelector('.el-dialog__header')
const dragDom = el.querySelector('.el-dialog')
dialogHeaderEl.style.cursor = 'move'
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)
dialogHeaderEl.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft
const disY = e.clientY - dialogHeaderEl.offsetTop
// 获取到的值带px 正则匹配替换
let styL, styT
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (sty.left.includes('%')) {
styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100)
styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100)
} else {
styL = +sty.left.replace(/\px/g, '')
styT = +sty.top.replace(/\px/g, '')
}
document.onmousemove = function(e) {
// 通过事件委托,计算移动的距离
const l = e.clientX - disX
const t = e.clientY - disY
// 移动当前元素
dragDom.style.left = `${l + styL}px`
dragDom.style.top = `${t + styT}px`
// 将此时的位置传出去
// binding.value({x:e.pageX,y:e.pageY})
}
document.onmouseup = function(e) {
document.onmousemove = null
document.onmouseup = null
}
}
}
})
// v-dialogDragWidth: 弹窗宽度拖大 拖小
Vue.directive('dialogDragWidth', {
bind(el, binding, vnode, oldVnode) {
const dragDom = binding.value.$el.querySelector('.el-dialog')
el.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - el.offsetLeft
document.onmousemove = function(e) {
e.preventDefault() // 移动时禁用默认事件
// 通过事件委托,计算移动的距离
const l = e.clientX - disX
dragDom.style.width = `${l}px`
}
document.onmouseup = function(e) {
document.onmousemove = null
document.onmouseup = null
}
}
}
})
// main.js中导入:import './utils/directives.js'
// 使用 el-dialog 的地方加入 v-dialogDrag
vue中实现超过两行显示展开,点击隐藏
<template>
<div class="view">
<div class="text more" ref="more">
占位
</div>
<div class="content" v-for="(item, index) in curData" :key="index">
<div class="text">
<div :class="{'retract': item.status}" :style="{'max-height':item.status ? textHeight: ''}" ref="textContainer">
{{item.desc}}
</div>
<div class="btn">
<p v-if="item.status" @click="item.status = false">展开</p>
<p v-if="item.status == false" @click="item.status = true">收起</p>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
curData: [
{ desc: '人物、情节、环境是小说的三要素。情节一般包括开端、发展、高潮、结局四部分,有的包括序幕、尾声。环境包括自然环境和社会环境。 小说按照篇幅及容量可分为长篇、中篇、短篇和微型小说(小小说)。按照表现的内容可分为神话、仙侠、武侠、科幻、悬疑、古传、当代、浪漫青春、游戏竞技等。按照体制可分为章回体小说、日记体小说、书信体小说、自传体小说。按照语言形式可分为文言小说和白话小说。' },
{ desc: '小说刻画人物的方法:心理描写、动作描写、语言描写、外貌描写、神态描写。' },
],
textHeight: null
}
},
methods: {
// 计算文字 显示展开 收起
calculateText() {
// 获取一行文字的height 计算当前文字比较列表文字
let oneHeight = this.$refs.more.scrollHeight
let twoHeight = oneHeight * 2 || 40
this.textHeight = `${twoHeight}px`
let txtDom = this.$refs.textContainer
for (let i = 0; i < txtDom.length; i++) {
let curHeight = txtDom[i].offsetHeight
if (curHeight > twoHeight) {
this.$set(this.curData, i, Object.assign({}, this.curData[i], { status: true }))
} else {
this.$set(this.curData, i, Object.assign({}, this.curData[i], { status: null }))
}
}
}
},
mounted() {
this.curData.forEach((ele, index) => {
this.$set(this.curData, index, Object.assign({}, ele, { status: null }))
})
// DOM 加载完执行
this.$nextTick(() => {
this.calculateText()
})
window.onresize = () => {
this.curData.forEach((ele, index) => {
this.$set(this.curData, index, Object.assign({}, ele, { status: null }))
})
setTimeout(() => {
this.calculateText()
}, 0)
}
},
destroyed(){
window.onresize = null;
}
};
</script>
<style>
.content {
display: flex;
margin-bottom: 30px;
}
.text {
position: relative;
font-size: 14px;
line-height: 20px;
letter-spacing: 2px;
color: #666666;
text-align: justify;
}
.retract {
position: relative;
overflow: hidden;
background: #fff;
}
.retract:after {
content: '...';
position: absolute;
bottom: 0;
right: 2px;
width: 25px;
padding-left: 5px;
padding-right: 30px;
background: linear-gradient(to right, transparent, #fff 0);
}
.btn {
position: absolute;
right: 0;
bottom: 0;
font-size: 14px;
line-height: 19px;
letter-spacing: 2px;
color: #FFAD41;
cursor: pointer;
}
p {
margin: 0;
}
.more {
font-size: 14px;
line-height: 20px;
letter-spacing: 2px;
color: #666666;
visibility: hidden;
}
</style>
基于vue实现头部上划显示下滑消失功能
<template>
<div class="about">
<div class="a-header" :class="['header--'+(isTopbarBlock ? 'show' : 'hidden')]">
<div class="header-top"></div>
<div class="header-bottom"></div>
</div>
<div class="a-main"></div>
</div>
</template>
<script>
export default {
data() {
return {
isTopbarBlock: true
}
},
mounted() {
let scrollingElement = document.scrollingElement
let scrollTop = 0
let that = this
window.addEventListener('scroll', () => {
if (scrollingElement.scrollTop < 300) {
that.isTopbarBlock = true
return
}
if (scrollingElement.scrollTop > scrollTop) {
that.isTopbarBlock = false
} else if (scrollingElement.scrollTop < scrollTop) {
that.isTopbarBlock = true
}
scrollTop = scrollingElement.scrollTop
})
},
}
</script>
<style lang="scss" scoped>
.about {
.a-header {
width: 100%;
height: 160px;
position: fixed;
top: 0;
left: 0;
transition: all .2s;
.header-top {
width: 100%;
height: 100px;
background: yellow;
}
.header-bottom {
width: 100%;
height: 60px;
background: green;
}
}
.header--show{
transform: translateY(0);
transition: all 1.2s;
}
.header--hidden{
transform: translateY(-100px);
transition: all 1.2s;
}
.a-main {
height: 5000px;
background: rgba(0,0,0,.5);
}
}
</style>
console.log
// log.js
const log = {};
/**
* @description 返回这个样式的颜色值
* @param {String} type 样式名称 [ primary | success | warning | danger | text ]
*/
function typeColor(type = "default") {
let color = "";
switch (type) {
case "default":
color = "#303133";
break;
case "primary":
color = "#409EFF";
break;
case "success":
color = "#67C23A";
break;
case "warning":
color = "#E6A23C";
break;
case "danger":
color = "#F56C6C";
break;
default:
break;
}
return color;
}
/**
* @description 打印一个 [ title | text ] 样式的信息
* @param {String} title title text
* @param {String} info info text
* @param {String} type style
*/
log.capsule = function(title, info, type = "primary") {
console.log(
`%c ${title} %c ${info} %c`,
"background:#35495E; padding: 1px; border-radius: 3px 0 0 3px; color: #fff;",
`background:${typeColor(
type
)}; padding: 1px; border-radius: 0 3px 3px 0; color: #fff;`,
"background:transparent"
);
};
/**
* @description 打印彩色文字
*/
log.colorful = function(textArr) {
console.log(
`%c${textArr.map((t) => t.text || "").join("%c")}`,
...textArr.map((t) => `color: ${typeColor(t.type)};`)
);
};
log.default = function(text) {
log.colorful([{ text }]);
};
log.primary = function(text) {
log.colorful([{ text, type: "primary" }]);
};
log.success = function(text) {
log.colorful([{ text, type: "success" }]);
};
log.warning = function(text) {
log.colorful([{ text, type: "warning" }]);
};
log.danger = function(text) {
log.colorful([{ text, type: "danger" }]);
};
export default log;
// home.js
log.default(">>> 我是一些默认提示");
log.primary(">>> 我是一些标记提示");
log.success(">>> 我是一些成功提示");
log.warning(">>> 我是一些警告提示");
log.danger(">>> 我是一些错误提示");
瀑布流
<template>
<div class="waterfall">
<div class="waterfall-left">
<div
class="waterfall-left-item"
v-for="(item, index) in waterLeft"
:key="index"
>
{{ item.content }}
</div>
</div>
<div class="waterfall-right">
<div
class="waterfall-right-item"
v-for="(ele, index) in waterRight"
:key="index"
>
{{ ele.content }}
</div>
</div>
</div>
</template>
<script>
export default {
name: "Home",
data() {
return {
waterInfo: [
{
content:
"世间有千万种相遇,而有种遇见叫做一见倾心,红尘中惊鸿的一瞥,你便凝眸在我内心深处,而我为这一眼就开始为你步步沦陷,只想有你温暖的陪伴别无它求,弱水三千取一瓢饮,只想独享你的世界,安静品读。守一份承诺细诉着爱恋,步入你温暖的城池,人的一生有诸多的美好,而我情有独钟的是与你相濡以沫。",
},
{
content:
"如果你的征途上有暴风雨,我愿把思念化作细丝,织成一把密密的友谊伞,让我们在暴风雨中走向胜境!",
},
{
content:
"只是因为在人群中多看了你一眼,使我忘不了你容颜,你可知弦断的哀鸣?为你种情盅爱毒,受尽辗转轮回。你若如知弦鸣的悲凉,那手指余温可否换一世相守,且不问前世转身,且不诉前世别离,任它人间花如雨,平生至爱你一人。默然,相爱。寂静,欢喜。",
},
{ content: "就让我们一直走下去,直到世界一片纯白。" },
{ content: "我醒了,想看看天上飘着的是,云做的雨还是雪做的云。" },
{
content:
"是谁,卷起秋风那无奈的萧瑟?是谁,在落花的泥土里浸染了无限的深情?是谁,点亮秋雨如针如丝的光芒?在秋雨深处,嗅到了寒凉的味道,让感觉缠绕丝丝缕缕秋的絮语。",
},
{ content: "时光的洪流中,我们总会长大。" },
{
content:
"飞机场的骚乱一会儿就停止了,这里的人都是有着自己的方向的,匆匆地起飞,匆匆地下降,带走别人的故事,留下自己的回忆。",
},
{
content:
"和善良对峙的,不一定只是邪恶。可能也是残酷。和理想对峙的,不一定只是世俗。可能也是天真。",
},
{
content:
"世间有千万种相遇,而有种遇见叫做一见倾心,红尘中惊鸿的一瞥,你便凝眸在我内心深处,而我为这一眼就开始为你步步沦陷,只想有你温暖的陪伴别无它求,弱水三千取一瓢饮,只想独享你的世界,安静品读。守一份承诺细诉着爱恋,步入你温暖的城池,人的一生有诸多的美好,而我情有独钟的是与你相濡以沫。",
},
{
content:
"如果你的征途上有暴风雨,我愿把思念化作细丝,织成一把密密的友谊伞,让我们在暴风雨中走向胜境!",
},
{
content:
"只是因为在人群中多看了你一眼,使我忘不了你容颜,你可知弦断的哀鸣?为你种情盅爱毒,受尽辗转轮回。你若如知弦鸣的悲凉,那手指余温可否换一世相守,且不问前世转身,且不诉前世别离,任它人间花如雨,平生至爱你一人。默然,相爱。寂静,欢喜。",
},
{ content: "就让我们一直走下去,直到世界一片纯白。" },
{ content: "我醒了,想看看天上飘着的是,云做的雨还是雪做的云。" },
{
content:
"是谁,卷起秋风那无奈的萧瑟?是谁,在落花的泥土里浸染了无限的深情?是谁,点亮秋雨如针如丝的光芒?在秋雨深处,嗅到了寒凉的味道,让感觉缠绕丝丝缕缕秋的絮语。",
},
{ content: "时光的洪流中,我们总会长大。" },
{
content:
"飞机场的骚乱一会儿就停止了,这里的人都是有着自己的方向的,匆匆地起飞,匆匆地下降,带走别人的故事,留下自己的回忆。",
},
{
content:
"和善良对峙的,不一定只是邪恶。可能也是残酷。和理想对峙的,不一定只是世俗。可能也是天真。",
},
],
waterLeft: [],
waterRight: [],
};
},
mounted() {
this.getData();
},
methods: {
getData() {
this.waterInfo.forEach((item, index) => {
if (index % 2 == 0) {
this.waterLeft.push(item);
} else {
this.waterRight.push(item);
}
});
},
},
};
</script>
<style lang="scss" scoped>
.waterfall {
width: 100%;
height: 100%;
overflow: auto;
display: flex;
flex-wrap: nowrap;
}
.waterfall-left,
.waterfall-right {
width: 50%;
height: 100%;
display: flex;
justify-content: center;
flex-wrap: wrap;
}
.waterfall-left-item,
.waterfall-right-item {
width: 100%;
height: auto;
padding: 20px;
font-size: 14px;
margin-bottom: 20px;
}
</style>
点击
<script>
!(function (e, t, a) {
function n() {
c(
".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"
),
o(),
r();
}
function r() {
for (var e = 0; e < d.length; e++)
d[e].alpha <= 0
? (t.body.removeChild(d[e].el), d.splice(e, 1))
: (d[e].y--,
(d[e].scale += 0.004),
(d[e].alpha -= 0.013),
(d[e].el.style.cssText =
"left:" +
d[e].x +
"px;top:" +
d[e].y +
"px;opacity:" +
d[e].alpha +
";transform:scale(" +
d[e].scale +
"," +
d[e].scale +
") rotate(45deg);background:" +
d[e].color +
";z-index:99999"));
requestAnimationFrame(r);
}
function o() {
var t = "function" == typeof e.onclick && e.onclick;
e.onclick = function (e) {
t && t(), i(e);
};
}
function i(e) {
var a = t.createElement("div");
(a.className = "heart"),
d.push({
el: a,
x: e.clientX - 5,
y: e.clientY - 5,
scale: 1,
alpha: 1,
color: s(),
}),
t.body.appendChild(a);
}
function c(e) {
var a = t.createElement("style");
a.type = "text/css";
try {
a.appendChild(t.createTextNode(e));
} catch (t) {
a.styleSheet.cssText = e;
}
t.getElementsByTagName("head")[0].appendChild(a);
}
function s() {
return (
"rgb(" +
~~(255 * Math.random()) +
"," +
~~(255 * Math.random()) +
"," +
~~(255 * Math.random()) +
")"
);
}
var d = [];
(e.requestAnimationFrame = (function () {
return (
e.requestAnimationFrame ||
e.webkitRequestAnimationFrame ||
e.mozRequestAnimationFrame ||
e.oRequestAnimationFrame ||
e.msRequestAnimationFrame ||
function (e) {
setTimeout(e, 1e3 / 60);
}
);
})()),
n();
})(window, document);
</script>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探