```
<template>
<div >
<!-- <a href="tel:13828172679">13622178579</a> -->
<div class="msg" ref="msg" v-html="html"></div>
<!-- 选择器 -->
<div class="start" ref="start" :style="{left: startL,top: startT}">
<i class="line"></i>
<div class="drag"></div>
</div>
<div class="end" ref="end" :style="{left: endL,top: endT}">
<i class="line"></i>
<div class="drag"></div>
</div>
<div class="end"></div>
<div class="mask" v-show="maskShow">
<div class="copy">复制</div>
<div class="search">查询</div>
<div class="error-recovery">纠错</div>
</div>
</div>
</template>
<script>
// 长按事件、选择改变、如果长度为0,咱们就不用显示
import anime from 'animejs'
export default {
/* 注意:名称是以文件名命名,如果冲突请修改 */
name: 'demo',
data () {
return {
maskShow: false,
html: '',
startT: '',
startL: '',
endL: '',
endT: ''
}
},
computed: {},
created(){
this.$nextTick((e) => {
// var text = '忽然想起那年夏日毕业之际,我送他的藏头巧妙情诗,还有在QQ的匿名坦白说,还有我第一次鼓起'
var text = `《普通高中语文课程标准(2017年版)》提出了语文学科核心素养——“语言建构与运用”“思维发展与提升”“审美鉴赏与创造”“文化传承与理解”。语文学科核心素养是对“三维目标”的升华,集中体现了新时代人才所应具备的必备品格和关键能力,为语文教学革新指明了方向。阅读在语文教学中是一个不可或缺的板块,阅读教学在语文教学中具有举足轻重的作用。语文学科核心素养的提出对阅读教学提出了更高的要求,最突出的表现为注重思维品质在阅读教学中的提升。所谓“研究性阅读教学”强调的是研究特性,追求阅读的广度和深度,着眼于高阶思维品质的培育。结合自身实习学段——高中,本人旨在依据2017年新版高中语文课标对思维品质培育的要求,建立起“思维发展与提升”的学科核心素养与“语文研究性阅读教学”之间的理论契合点,结合思维发展的阶段理论,就语文研究性阅读教学理念发表自己的见解,并就语文研究性阅读教学策略提出自己的设想。除绪论和结语之外,正文共分为五个部分:第一部分:本人旨在从阅读教学入手,分析新课程背景下高中语文学科对于阅读能力的培养要求,对“语文研究性阅读教学”进行概念界定。同时,本人还将阐述推行语文研究性阅读教学的意义。第二部分:本人依据语文教育实际,总结分析语文阅读教学现状,指出现行阅读教学主要存在着深度缺乏、形式化倾向、思维培育不够等问题。同时,本人将概述课改先行区特级教师的一些成功做法,以供借鉴。第三部分:理念是实践的先导。本人旨在提出自己对语文研究性阅读教学理念的认识:增强问题研究能力,注重思维方式规训,推行深度阅读教学。第四部分:在上述理念的指导下,就高中语文研究性阅读教学策略提出自己的设想——任务驱动、专题研习、拓展迁移、批判反思。在此部分本人结合相关教学案例进行阐释分析,以支撑自己的论述。第五部分:指出践行语文研究性阅读教学的局限性,以及应该处理好的四对关系。`
let str = ''
for(var i=0;i < 100;i++) {
var len = text.length;
str += '<div class="list">'
for(var k=0;k < len;k++) {
str += '<span data-index="'+ k +'">' + text[k] + '</span>'
}
str += '</div>'
}
this.html = str
/**
* 1、长按的话,获取当前选中的文本对象
* 2、如果按到哪里的源为空,则全新当前这段,这段的第一个和最后一个选中
* 3、如果按到的是span标签的话,
* 优化:长按后,获取下面整个dom节点,通过不移动到哪个位置,来定位
* 先查询当前选中了几个文本,然后在根据这些文本选中的索引来
* 限制拉出这个list宽度高度
* 复制、查询、弹窗位置,当在最顶上最侧边
*/
var maxH = 0, // 滑到高度最大位置
maxW = 0, // 滑到宽度最大位置
mouseTime = 0, // 长按时间
listOfset = null, // 每列距离上面左边多少
listChildren = [], // 存储长按整段文字距离屏幕多少
selectTxtDom = [], // 选中的所以文本
allListChildrenDom = [], // 整个一段文本所有的dom
flagDarg = false, // 拖拽开关
that = this; // 当前vue对象
var startIndex = 0,
endIndex = 0,
startDragIndex = 0 // 拖拽开始位置到某个地方停止了,进行标记在哪个位置上
// 滚动监听
let win = window
let scrollY = win.screenY
let maxTop = 0
let tParent = null; // 父节点
let timer2 = null; //
win.addEventListener('scroll',(i) => {
scrollY = win.scrollY
if(tParent) {
maxTop = tParent.parentNode.getBoundingClientRect().top
}
// 更新 listChildren 里面的数据
clearTimeout(timer2)
timer2 = setTimeout(() => {
let len = allListChildrenDom.length
for(var i=0;i<len;i++) {
listChildren[i] = allListChildrenDom[i].getBoundingClientRect()
}
}, 300);
})
this.$nextTick(() => {
var list = this.$refs.msg.querySelectorAll('.list');
let len = list.length;
for(var i=0;i<len;i++) {
list[i].ontouchstart = function () {
mouseTime = new Date().getTime()
}
list[i].ontouchend = function (e) {
if(new Date().getTime() - mouseTime >= 500) { // 长按了,如果是滚动的了话,证明不需要
// 清除之前选中的文本样式
let subLen = allListChildrenDom.length
for(var k=0;k<subLen;k++) {
allListChildrenDom[k].style.backgroundColor = ''
allListChildrenDom[k].style.color = ''
}
// 存储下当前选中的这段文本文字距离屏幕多少
allListChildrenDom = this.children
subLen = allListChildrenDom.length
listChildren = []
for(var k=0;k < subLen;k++) {
listChildren.push(allListChildrenDom[k].getBoundingClientRect())
}
// 获取当前的
var domWrap = window.getComputedStyle(this)
maxW = domWrap.width
maxW = Number(maxW.slice(0,maxW.length-2));
maxH = domWrap.height
maxH = Number(maxH.slice(0,maxH.length-2));
listOfset = this.getBoundingClientRect();
maxW = maxW + listOfset.left
maxH = maxH + listOfset.top - that.$refs.start.offsetHeight + 5;
console.log(maxW, maxH);
selectTxtDom = []
selectTxtDom.push(e.target)
if(e.target.nodeName === 'SPAN') {
// 当前长按选择的dom对象,x轴与y轴
tParent = e.target
var clientRect = tParent.getBoundingClientRect()
startIndex = Number(e.target.dataset.index) // 获取当前选中的第几个dom
// 当前文字结束位置与
endIndex = startIndex == allListChildrenDom.length-1 ? startIndex + 1 : startIndex // 获取当前选中的第几个dom
that.startL = clientRect.left + 'px'
that.startT = clientRect.top + scrollY + 'px'
that.endL = clientRect.right + 'px'
that.endT = clientRect.top + scrollY + 'px'
e.target.style.backgroundColor = 'rgba(60,172,243,.4)'
e.target.style.color = '#39789f'
}else { // 空格或者是当前,选择全部的
}
}
}
}
})
// 开始位置拖拽
var endPostion = null;
uDrags(this.$refs.start,{
dragStart:function (msg) {
flagDarg = true
endPostion = listChildren[endIndex]
// console.log(listChildren,'listChildren');
},
dragging:function (msg) {
/**
* “开始位置”的x轴与y轴都得限制在“结束位置”x轴与y轴之间:
* 1、每次都得检查y轴与x轴位置
* 2、当y轴在可行范围内则x轴就可以跑
* 3、当x轴在可行范围内则y轴就可以跑
*/
if(msg.top + endPostion.height < endPostion.top) {
that.startL = msg.left + 'px'
if(msg.top > 0) {
that.startT = msg.top + scrollY + 'px'
}
checkText(msg)
}else if(msg.left < endPostion.left && msg.left > listOfset.left) {
that.startL = msg.left + 'px'
if(msg.top <= endPostion.top) {
that.startT = msg.top + scrollY + 'px'
}
checkText(msg)
}
},
dragEnd:function (msg) {
flagDarg = false
// 松手后,将去除下
let postion = listChildren[startDragIndex]
that.startT = postion.top + scrollY + 'px'
that.startL = postion.left + 'px'
}
})
// 结束位置拖拽
var startIndex = null;
uDrags(this.$refs.end,{
dragStart:function (msg) {
console.log(listChildren,'listChildren');
},
dragging:function (msg) {
// 不能超过选中的一段文本最左边距离与右边距离
if(msg.left < maxW && msg.left > listOfset.left) {
// if() { // 不能超过开始位置
// }
that.endL = msg.left + 'px'
}
// 不能超过选中的一段文本最上边距离与下边距离
if(msg.top > listOfset.top && msg.top < maxH) {
that.endT = msg.top + 'px'
}
//
},
dragEnd:function (msg) {
}
})
// 检测选中的某个部分文字
function checkText (msg) {
/**
* == 开始标记位置不能超过结束位置。如果是结束位置不能超过开始位置 ==
* 开始位置:
* 开始位置的标记,
*/
// 限制结束区域
for(var i=0;i<startIndex;i++) {
/**
* 从开始值到结束值中间取dom
* 1、得看top值与left值
*/
if(listChildren[i].left >= msg.left && listChildren[i].top >= msg.top - listChildren[i].height) {
// console.log(,'listChildren[i]');
startDragIndex = i; // 拖拽,选中的开始拖拽是这个地方
for(var s = 0;s<i;s++) {
allListChildrenDom[s].style.backgroundColor = ''
allListChildrenDom[s].style.color = ''
}
for(var k=i;k<endIndex;k++) {
allListChildrenDom[k].style.backgroundColor = 'rgba(60,172,243,.4)'
allListChildrenDom[k].style.color = '#39789f'
}
break;
}
}
}
// 拖拽
function uDrags (dom,cbJson) {
var cbJson = cbJson || {}
let msg = {
dom:dom,
dragging:false,
isClick:false,
startX:0,
startY:0,
domX:0,
domY:0,
left:0,
top:0,
x:0,
y:0,
dTop:0, // 直接可以使用
dLeft:0,
isDOM : ( typeof HTMLElement === 'object' ) ?
function(obj){
return obj instanceof HTMLElement;
} :
function(obj){
return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
},
getStyle:function (obj,attr){
return obj.currentStyle?obj.currentStyle:getComputedStyle(obj);
}
}
var dTop ='',dLeft=''
// instanceof HTMLElement 兼容性不好
if(!msg.isDOM(dom)) {
return console.warn('err:错误,这个不是dom')
}
dom.addEventListener('touchstart', down)
dom.addEventListener('mousedown',down)
var windowFlags = false;
function down (event) {
windowFlags = false;
event.preventDefault();// 阻止默认事件
if (event.type === 'touchstart') {
event.clientY = event.touches[0].clientY;
event.clientX = event.touches[0].clientX;
}
// 获取基本信息
msg.dragging = true; // 按下了
msg.isClick = true; // 在点击状态
msg.startX = event.clientX; // 获取浏览器左边缘鼠标位置
msg.startY = event.clientY; // 获取浏览器右边缘鼠标位置
msg.domX = msg.startX - dom.getBoundingClientRect().left; // dom的左边边缘与按下去鼠标的位置
msg.domY = msg.startY - dom.getBoundingClientRect().top; // dom的上边边缘与按下去鼠标的位置
var styles = msg.getStyle(msg.dom)
dTop = parseFloat(styles.top);
dLeft = parseFloat(styles.left);
cbJson.dragStart(msg)
// 并且添加事件
window.addEventListener('mousemove', onDragging); // 监听当前移动
window.addEventListener('touchmove', onDragging); // 监听当前移动
window.addEventListener('mouseup', onDragEnd); // 添加抬起事件
window.addEventListener('touchend', onDragEnd);// 添加抬起事件
window.addEventListener('contextmenu', onDragEnd); // 右击事件
if (self != top) {
let subWin = window;
// 解决嵌入到iframe中,滑动的太快,出去了,没有执行 dragEnd 回调
window.parent.addEventListener('mousemove', function (ev) {
if (windowFlags) {
return;
}
windowFlags = true;
cbJson.dragEnd(msg);
subWin.removeEventListener('mousemove', onDragging);
subWin.removeEventListener('touchmove', onDragging);
subWin.removeEventListener('mouseup', onDragEnd);
subWin.removeEventListener('touchend', onDragEnd);
subWin.removeEventListener('contextmenu', onDragEnd);
ev.preventDefault();
}, false)
}
}
// 监听拖着
function onDragging (event) {
if (msg.dragging) {
msg.isClick = false;
if(event.type === 'touchmove') {
event.clientY = event.touches[0].clientY;
event.clientX = event.touches[0].clientX;
}
msg.x = event.clientX;
msg.y = event.clientY;
msg.left = msg.x - msg.domX;
msg.top = msg.y - msg.domY;
msg.dTop = dTop + msg.y - msg.startY;
msg.dLeft = dLeft + msg.x - msg.startX;
if(cbJson.dragging && typeof cbJson.dragging === 'function') {
cbJson.dragging(msg)
}
}
}
// 监听拖拽放开
function onDragEnd (e) {
if (msg.dragging) {
/*
* 防止在 mouseup 后立即触发 click,导致滑块有几率产生一小段位移
* 不使用 preventDefault 是因为 mouseup 和 click 没有注册在同一个 DOM 上
*/
setTimeout(function (){
msg.dragging = false;
if (!msg.isClick) {
if(cbJson.dragEnd && typeof cbJson.dragEnd === 'function') {
windowFlags = true
cbJson.dragEnd(msg)
// msg = null;
}
}
}, 0);
window.removeEventListener('mousemove', onDragging);
window.removeEventListener('touchmove', onDragging);
window.removeEventListener('mouseup', onDragEnd);
window.removeEventListener('touchend', onDragEnd);
window.removeEventListener('contextmenu', onDragEnd);
}
}
// 取消事件
return function off (offDom) {
if(Array.isArray(offDom)) {
var len = offDom.length;
for(var i=0;i<len;i++) {
if(msg.isDOM(offDom[i])) {
offDom[i].removeEventListener('mousedown',down)
offDom[i].removeEventListener('touchstart',down)
}
}
}else if(msg.isDOM(offDom)) {
offDom.removeEventListener('mousedown',down)
offDom.removeEventListener('touchstart',down)
}
}
}
// window.addEventListener('contextmenu', function(e){
// e.preventDefault();
// },false)
// 取消之后右键就没有菜单了document.oncontextmenu = function(e){
document.oncontextmenu = function(e){
var event = e||window.event;
event.stopPropagation()
if(e.preventDefault){
e.preventDefault();
}else{
event.returnValue = false;
}
}
// document.body.addEventListener('touchmove' , function(e){
// var e=e||window.event;
// e.preventDefault();
// },{ passive: false })
var timer = null;
var mask = document.querySelector('.mask'),
that = this;
document.onselectionchange = function(e) {
let str = ''
let select = window.getSelection()
console.log(select,'');
clearTimeout(timer)
timer = setTimeout(() => {
str = select.toString()
that.maskShow = !!str
},100)
};
})
function selectText(element) {
if (document.body.createTextRange) {
let range = document.body.createTextRange();
range.moveToElementText(element);
range.select();
} else if (window.getSelection) {
let selection = window.getSelection();
let range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
} else {
alert('none');
}
}
},
methods: {}
}
</script>
<style lang="scss" scoped>
p {
-webkit-touch-callout: none;
}
.mask {
-moz-user-select: none; /*火狐*/
-webkit-user-select: none; /*webkit浏览器*/
-ms-user-select: none; /*IE10*/
-khtml-user-select: none; /*早期浏览器*/
user-select: none;
width: 100%;
height: 40px;
background: aqua;
position: fixed;
left: 0;
bottom: 0;
display: flex;
justify-content: space-between;
}
div {
-moz-user-select: none; /*火狐*/
-webkit-user-select: none; /*webkit浏览器*/
-ms-user-select: none; /*IE10*/
-khtml-user-select: none; /*早期浏览器*/
}
.msg {
/deep/ .list {
font-size: 1.5rem;
margin: 1rem 0;
}
}
.start,.end {
position: absolute;
left: 0;
top: -222;
}
.start,.end {
height: 2.5rem;
.line {
width: .1rem;
height: 2.5rem;
background-color: #3CACF3;
display: block;
}
.drag {
width: 1.4rem;
height: 1.4rem;
background: #3CACF3;
position: absolute;
top: 2rem;
left: -.8rem;
border-radius: 100%;
}
}
// p {
// // pointer-events: none;
// -webkit-touch-callout: none;
// }
// * {
// -webkit-touch-callout: none;
// }
</style>
```
- LOLKU
- 工具类
- form/formData
- form
- formData
- iframe
- 渲染数据,防止内存泄漏
- 获取url(路由)参数
- 常用方法
- 失去焦点软键盘页面乱
- 判断数据类型
- 浏览器全屏
- 动态插入css
- 随机生成自定义长度位数数字
- 验证判断
- localStorage 封装存储
- 格式化日期
- 计算两个时间差
- 去除空格
- 将驼峰命名转换为连字符
- 获取dom属性
- 深拷贝
- class操作
- 判断是否打开浏览器控制台
- 全国城市地区代码表
- canvas合成工具
- 去除emoji表情符号
- 比较两个对象属性和内容(值)一致
- 微信结束页面事件
- 正则匹配url替换域名
- 字符串拼接(渲染dom后传值)
- 判断是否是正则
- 日历算法
- json 工具
- 是否支持webp格式
- h5底部输入框被键盘遮挡问题
- php
- php 二级域名管理
- 单个或者多个域名跨域
- file_get_contents 正确使用
- fromData请求无法携带cookie
- 简单的加密文件传输
- css
- 1px
- 滚动
- ios点击有颜色
- 文本溢出省略号
- css动画抖动
- 文本换行与不换行
- 阻止旋转屏幕时自动调整字体大小
- vue
- vscode 调试
- 新技术
- vue-router 4.0
- vue3
- 基础
- 试验
- javascript
- 上传问题
- 文件选中过,第二次再次选中不触发change事件
- 上传oss
- 后台
- linux搭建服务
- 需安装
- nginx
- 安装
- nginx http 配置二级域名
- nginx https 配置二级域名
- 防止暴力破解
- 阿里申请免费https
- git
- 快速安装
- 配置项
- node
- 安装
- pm2
- mysql
- 安装
- 创建、切换、查询数据库
- 常用命令
- cmake 编译器
- redis
- 软件下载
- git
- 百度git 记住密码
- 经验
- 上传
- 软件
- vscode
- 推荐插件
- 应用开发
- nwjs
- 入门
- package.json
- vue、react、angular 跑nwjs
- 打包
- 监听屏幕
- 运行另一个.exe文件
- node应用
- electron
- 资料
- 安装
- 实战
- 崩溃日志报告
- electron-forge
- 托盘闪烁
- 开机自动启动
- 消息通知
- 禁止默认事件
- 保证只有一个实例
- 打包且美化安装界面
- 创建cli
- 添加Github徽章
- 自动更新
- docsify
- Lowdb存储数据
- 备份、恢复、导入、导出
- 深度链接(协议)唤起Electron应用
- 说明
- 加载扩展插件
- 证书
- Sketch 插件
- 工作
- 宣传文章地址
- api
- tinypng
- npm 插件
- fs封装:fs-jetpack
- 判断是否npm或yarn运行
- 字符串或缓冲区的gzip压缩大小
- 克隆并修改RegExp实例
- 反转对象的键/值
- http路由find-my-way
- dragula 拖拽(拖放)
- svga
- npm 脚手架搭建
- 项目
- 小工具
- svg转图片
- 日历