首页
Search
1
解决visual studio code (vscode)安装时没有选择安装路径问题
138 阅读
2
Linux 下 Bash 脚本 bad interpreter 报错的解决方法
131 阅读
3
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
107 阅读
4
如何在 Clash for Windows 上配置服务
77 阅读
5
Uniapp如何引入自定义样式文件
75 阅读
clash
服务器
javascript
全部
游戏资讯
登录
Search
加速器之家
累计撰写
1,061
篇文章
累计收到
0
条评论
首页
栏目
clash
服务器
javascript
全部
游戏资讯
页面
搜索到
1061
篇与
的结果
2024-10-21
原生js实现简单的链式操作
在jQuery中,一个jq对象能一直连续调用各种方法,因为jQuery把这些方法挂载他自定义的一个对象中,但是使用原生的js获取的DOM对象,只能使用一次addEventLisenter方法添加事件,如果要接着添加事件,还得再调用addEventLisenter。var area = document.querySelector('.area'); area.addEventListener('mouseenter', function(){ console.log( 'mouse enter' ); }); area.addEventListener('click', function(){ console.log( 'click' ); }); 可是如果我想在area绑定mouseenter事件后,接着绑定click事件呢。我们也可以参考下jQuery的实现思路,但是没jQuery这么完善。;(function(){ window.G = function(selector){ return new _G(selector); } function _G(selector){ this.elements = document.querySelector(selector); return this; } _G.prototype = { constructor : _G, method : function(name, fn){ if(this.elements){ this.elements.addEventListener(name, fn, false); } return this; } } })(); 这样我们就能实现一个简单的链式调用了,给.area同时绑定两个事件:G('.area').method('mouseenter', function(){ console.log( 'mouse enter' ); }).method('click', function(){ console.log( 'click' ); }) 实现原理相信大家看到代码也非常的清楚: 输出一下G('.area'),他返回的就是一个_G的实例对象; 在_G的内部,把DOM对象存储在elements上,然后prototype上实现了method方法,就是给elements添加对应的事件,每次调用后,都把this返回,供下次使用; G('.area')就能使用使用method方法来添加事件了,同时每次method都会把this返回,这样就能连续添加事件 上面的代码我们只是实现了如何为DOM对象连续添加事件,当然我们还可以在_G.prototype中添加别的方法,不过别忘记了return this: _G.prototype = { constructor : _G, method : function(name, fn){ if(this.elements){ this.elements.addEventListener(name, fn, false); } return this; }, show : function(){ this.elements.style.display=''; return this; }, hide : function(){ this.elements.style.display='none'; return this; } } 这样G()就能使用show()和hide()了:// 隐藏 G('.area').hide(); // 显示并且绑定click事件 G('.area').show().method('click', function(){ console.log( Date.now() ); }) 注意: G('.area')不是原生的DOM对象,不能直接操作DOM对象上的属性与方法,比如我想隐藏.area:G('.area').style.display='none'; // 错误 是不能这么操作的。DOM对象存储在elements中,如果想直接在DOM对象上操作,可以:G('.area').elements.style.display='none'; // 正确 总结一下,这里我们也只是用原生js简单的实现了下链式操作,更复杂的功能,比如对象缓存,异常处理等等,都需要后续再完善处理。
2024年10月21日
5 阅读
0 评论
0 点赞
2024-10-21
使用vue实现tab操作
在使用jQuery类库实现tab功能时,是获取鼠标在mousenter或click时的index值,然后切换到当前的标题和内容,把其他的标题和内容的状态去掉:$('.tab .title').find('.item') .removeClass('current').eq(index).addClass('current'); // 为index位置的title添加current $('.tab .content').find('.item') .hide().eq(index).show(); // 显示index位置的内容 那么在使用vue实现tab功能时,就不是像jQuery这种直接操作DOM了。我这里总结了下实现tab功能的3个思路,仅供参考。 1. 切换content或者直接切换内容 # 这种思路下,我们首先把结构搭建起来,然后用一个变量selected表示tab当前展示的位置,给li标签添加mouseenter或click事件,将当前的index传递进去:html代码: {{item.title}} js代码:var app = new Vue({ el: '#app', data: { selected: 0, //当前位置 list: [ { title: '11111', content: '11111content' }, { title: '22222', content: '222222content' }, { title: '33333', content: `hello world{{message}}` } ] }, methods: { change(index) { this.selected = index; } } }) 绑定的change(index)事件,每次都将index给了selected,然后tab就会切换到对应的标签。【查看实例1】上面的代码里,我们是通过切换div的显示与隐藏来进行执行的。tab中的content里如果只有纯html内容,我们可以直接把list[selected].content展示到.bd中: 每次selected变换时,bd的内容都会发生变化。 2. 使用currentView # 在上面的实现方式中,第3个tab里有个输入框与p标签双向绑定,但是没有效果,因为vue是把list中的内容作为html元素填充到页面中的,message并没有作为vue的属性绑定给input。那么使用组建和currentView就能弥补这个缺陷。无论使用全局注册还是局部注册的组件,思路都是一样的,我们暂时使用全局注册的组件来实现。每个组件里展示的是一个tab里的内容,先注册3个组件:// tab0 Vue.component('item0',{ template : '1111111content' }); // tab1 Vue.component('item1',{ template : '222222content' }) // tab2 Vue.component('item2',{ data(){ return{ message : '' } }, template : `hello world{{message}}` }) 然后在html中使用component来展示对应组件的内容,title的展示方式不变: {{item.title}} currentView属性可以让多个组件可以使用同一个挂载点,并动态切换:var app = new Vue({ el: '#app', data: { selected: 0, currentView : 'item0', list: [ { title: '11111' }, { title: '22222' }, { title: '33333' } ] }, methods: { change(index) { this.selected = index; this.currentView = 'item'+index; // 切换currentView } } }) 这样 message 在组件里就是一个独立的data属性,能在tab里也使用vue绑定事件了【查看实例2】。 3. 使用slot方式等 # 使用slot方式进行内容分发或者一个独立的组件,可以让我们把代码整合到一块,对外提供一个数据接口,只要按照既定的格式填写数据即可。 3.1 slot # 用slot方式写一个子组件:Vue.component('my-slot-tab', { props : ['list', 'selected'], template : ` ` }); 父组件模板: {{ props.text }} 父组件中slot="title"会替换子组件中name="title"的slot,父组件中slot="content"会替换子组件中name="content"的slot.最终渲染出来的tab结构与上面之前的代码一样。【查看实例3-1】 3.2 其他组件方式 # 还有一种方式就是把所有的模板都写到组件中。子组件:Vue.component('my-tab', { props : ['list'], template : ` {{item.title}} `, data(){ return{ selected:0 } }, methods : { change(index){ this.selected = index; } } }); 父组件: 这种只需要传递一个list即可。【查看实例3-2】对比这两种方法,slot中可以自定义更多的内容,而下面的方法使用起来更加简单,只是自定义的东西比较少。 4. 总结 # 上面讲解了几种实现tab功能的方式,没有说哪种方式最好,选择最适合自己项目需求的方式就是最好的。文中有哪有错误或不足,欢迎批评指正。
2024年10月21日
8 阅读
0 评论
0 点赞
2024-10-21
用CSS3实现无限循环的无缝滚动
有时候在页面的某个模块中,需要无限循环的滚动一些消息。那么如果我们用js实现无缝衔接滚动的思路是什么呢(比如我们这个模块是向上滚动的)? 克隆A一份完全一样的数据B放在原数据A的后面; 使用setInterval向上滚动A的父级容器; 当向上滚动的距离L正好的A的高度时(L==A.height()),L=0,重新开始滚动,无限循环。 克隆一份数据放在后面,是为了当A向上移动时,后面有数据能填补漏出来的空白。当B移动到可视区域的顶部时,此时A刚好移出可视区域,那么此时将容器重新归0,用户是没有感知的,以为还是B中的第一条数据。然后继续向上滚动。 1. 使用CSS3来实现 # 若要用CSS3的属性实现的话,非animation莫属,因为transition是需要手动的触发,而且不能无限次执行下去,而animation恰好能解决这个问题。假如数据是在写死的情况下时,我们完全可以手动复制一份数据放在后面,然后把原数据的高度写到css中,实现的思路与上面的一样:css:@keyframes rowup { 0% { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } 100% { -webkit-transform: translate3d(0, -307px, 0); transform: translate3d(0, -307px, 0); } } .list{ width: 300px; border: 1px solid #999; margin: 20px auto; position: relative; height: 200px; overflow: hidden; } .list .rowup{ -webkit-animation: 10s rowup linear infinite normal; animation: 10s rowup linear infinite normal; position: relative; } html: 1- 121233fffffr国家认可更健康进口价格困扰 2- 3123233 3- 个人口结构俄跨入国际科技馆客人感觉 4- ggrgerg 5- fvdgdv 6- 德国南部巴士与卡车相撞起火 31人受伤11人死亡朴槿惠庭审时突然昏迷 支持者:她死了法官要负责! 7- 外交部再次回应印军越界:要求立即将越界部队撤回 8- 德国网红致信默克尔 9- 国资委原 1- 121233fffffr国家认可更健康进口价格困扰 2- 3123233 3- 个人口结构俄跨入国际科技馆客人感觉 4- ggrgerg 5- fvdgdv 6- 德国南部巴士与卡车相撞起火 31人受伤11人死亡朴槿惠庭审时突然昏迷 支持者:她死了法官要负责! 7- 外交部再次回应印军越界:要求立即将越界部队撤回 8- 德国网红致信默克尔 9- 国资委原 运行的效果如下: 1- 121233fffffr国家认可更健康进口价格困扰2- 31232333- 个人口结构俄跨入国际科技馆客人感觉4- ggrgerg5- fvdgdv6- 德国南部巴士与卡车相撞起火 31人受伤11人死亡朴槿惠庭审时突然昏迷 支持者:她死了法官要负责!7- 外交部再次回应印军越界:要求立即将越界部队撤回8- 德国网红致信默克尔9- 国资委原1- 121233fffffr国家认可更健康进口价格困扰2- 31232333- 个人口结构俄跨入国际科技馆客人感觉4- ggrgerg5- fvdgdv6- 德国南部巴士与卡车相撞起火 31人受伤11人死亡朴槿惠庭审时突然昏迷 支持者:她死了法官要负责!7- 外交部再次回应印军越界:要求立即将越界部队撤回8- 德国网红致信默克尔9- 国资委原 2. 数据不确定时 # 在上面的小节中,数据是死的,高度也是写死到了CSS3中。可是如果从接口获取到的数据个数不定呢,每条数据的长度也不确定,怎么办呢?这里就需要根据数据来重新计算高度,并写到CSS里,可是keyframes修改起来还比较麻烦,那么我们就用覆盖的方式来重新keyframes中的数据:// 设置keyframes属性 function addKeyFrames(y){ var style = document.createElement('style'); style.type = 'text/css'; var keyFrames = '\ @-webkit-keyframes rowup {\ 0% {\ -webkit-transform: translate3d(0, 0, 0);\ transform: translate3d(0, 0, 0);\ }\ 100% {\ -webkit-transform: translate3d(0, A_DYNAMIC_VALUE, 0);\ transform: translate3d(0, A_DYNAMIC_VALUE, 0);\ }\ }\ @keyframes rowup {\ 0% {\ -webkit-transform: translate3d(0, 0, 0);\ transform: translate3d(0, 0, 0);\ }\ 100% {\ -webkit-transform: translate3d(0, A_DYNAMIC_VALUE, 0);\ transform: translate3d(0, A_DYNAMIC_VALUE, 0);\ }\ }'; style.innerHTML = keyFrames.replace(/A_DYNAMIC_VALUE/g, y); document.getElementsByTagName('head')[0].appendChild(style); } 计算出原始数据A的高度后,执行 addKeyFrames 方法,往head中添加css属性,那么这里的rowup就会覆盖掉之前设置的,每次滚动的距离就是数据A的高度:function init(){ var data = '塞下秋来风景异,衡阳雁去无留意。四面边声连角起,千嶂里,长烟落日孤城闭。浊酒一杯家万里,燕然未勒归无计。羌管悠悠霜满地,人不寐,将军白发征夫泪。', //样例数据 data_len = data.length, len = parseInt(Math.random()*6)+6, // 数据的长度 html = ''; for(var i=0; i { const uid = Math.random().toString(36).substr(2); const style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = `@-webkit-keyframes rowup${uid} { 0% { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } 100% { -webkit-transform: translate3d(0, -50%, 0); transform: translate3d(0, -50%, 0); } } @keyframes rowup${uid} { 0% { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } 100% { -webkit-transform: translate3d(0, -50%, 0); transform: translate3d(0, -50%, 0); } } .rowup-${uid}{ -webkit-animation: ${Math.floor(offsetHeight*1000 / speed)}ms rowup${uid} linear infinite normal; animation: ${Math.floor(offsetHeight*1000 / speed)}ms rowup${uid} linear infinite normal; }` document.getElementsByTagName('head')[0].appendChild(style); return `rowup-${uid}`; } componentDidMount() { const scrollContent: HTMLElement | null = document.querySelector('.scroll .scroll-content'); if (scrollContent) { const offsetHeight = scrollContent.offsetHeight; const scrollClass = this.setScrollStyle(offsetHeight / 2, this.props.speed || 35); this.setState({ rollClass: scrollClass }); } } render() { const rollClass = this.state.rollClass ? ' ' + this.state.rollClass : ''; return ( {this.props.children} {this.props.children} ); } } 使用方式: 1 2 3 4 5 6 7 8 1 2 3 4 5 3. 横向滚动 # 上面讲解的都是向上滚动,那么向左,向右,向下也比较容易理解了,把transform中的值更改为对应的数值即可。 4. 总结 # 使用CSS来进行动画的展示,会让页面显得更加流畅。如果能用CSS实现,可以尝试尽量用CSS实现下。
2024年10月21日
11 阅读
0 评论
0 点赞
2024-10-21
vue实现对数据的增删改查(CURD)
在管理员的一些后台页面里,个人中心里的数据列表里,都会有对这些数据进行增删改查的操作。比如在管理员后台的用户列表里,我们可以录入新用户的信息,也可以对既有的用户信息进行修改。在vue中,我们更应该专注于对数据的操作和处理。比如我们有一个这样的页面:我们在这个页面里,就实现了增删改查4个功能,点击链接查看demo。我们把这些用户信息保存到list的数组中,然后增删改查就在这个数组上进行:list: [ { username: 'aaaaa', email: '123@qq.com', sex: '男', province: '北京市', hobby: ['篮球', '读书', '编程'] }, { username: 'bbbbb', email: 'bbbbbbb@163.com', sex: '女', province: '河北省', hobby: ['弹琴', '读书', '插画'] } // ... ] 设置这些数据主要也是复习一下vue对表单的处理操作,这里面的表单有:文本输入框,单选按钮,select选择框,复选框等。 1. 展示数据 # 我们的数据都放在数组list中,但是这里并不直接对list对循环输出,而是先把list中的数据给一个数组slist,对slist进行循环输出。因为我们在后面的查询功能中需要对数据进行过滤,数组list一直保存着原始数据(包括新增、修改后或已删除后),而数组slist只负责展示。在vue中提供一个setSlist方法,将需要展示的数据给了数组slist:// 获取需要渲染到页面中的数据 setSlist(arr) { this.slist = JSON.parse(JSON.stringify(arr)); } 然后在html中使用v-for把slist数组渲染出来: {{index+1}} {{item.username}} {{item.email}} {{item.sex}} {{item.province}} {{item.hobby.join(' | ')}} 修改 | 删除 在操作这一栏中,给修改和删除操作绑定上事件。 2. 增加和删除功能 # 把增加功能和删除合并到一起,是这两个功能相对来说都比较简单。增加用户时使用push方法,把用户的信息添加到list数组的最后:this.list.push({ username: 'ffff', email: 'fffffff@163.com', sex: '女', province: '河南省', hobby: ['弹琴', '插画'] }); 这样就能添加一位ffff的用户了。删除用户时,通过splice(index, 1),可以删除index位置的数据,页面上的数据自动就会更新。 3. 修改功能 # 当我们想要修改某个元素时,可以把这个位置上的数据取出来放到弹层里(或者其他某个位置),在弹层里的信息可以取消或者修改后进行保存。假设我们弹层里的数据是selectedlist,那么每次修改时,把index位置的数据给了selectedlist,然后在弹层中修改selectedlist。我们也能看到修改数据的类型: 文本框(用户名,邮箱),单选按钮(性别),select选择框(所在省份),多选框(爱好),这里我们主要练习的是表单处理(https://cn.vuejs.org/v2/guide/forms.html)。弹层是否显示用变量isActive来控制:// 修改数据 modifyData(index) { this.selected = index; // 修改的位置 this.selectedlist = this.list[index]; this.isActive = true; } 有没有发现一个问题,当修改弹层中的信息时,表格中的数据也同步更新了。可是我们本身是希望当点击保存按钮时,才把弹层中的数据保存到表格里。问题的根源就出在这里:this.selectedlist = this.list[index]; 因为list[index]是个Object类型的数据,若使用**=**赋值,则赋值操作为浅度拷贝(把数据的地址赋值给对应变量,而没有把具体的数据复制给变量,变量会随数据值的变化而变化),selectedlist与list[index]使用相同的数据地址,互相引起数据值的变化。因此这里我们需要进行深度拷贝:this.selectedlist = JSON.parse( JSON.stringify(this.list[index]) ); // 先转换为字符串,然后再转换 当用户修改数据后,selectedlist就会发生变化,点击保存按钮时,将数据重新保存到index位置:/* this.list 数据数组 this.selected 刚才修改的位置 this.selectedlist 需要保存的数据 */ Vue.set(this.list, this.selected, this.selectedlist); 4. 查询功能 # 在第1小节中我们已经说过,在页面表格中展示的是slist中的数据,就是为了方便执行查询操作:// 获取需要渲染到页面中的数据 setSlist(arr) { this.slist = JSON.parse(JSON.stringify(arr)); } 每次根据某些条件将过滤后的数据赋值给slist数组,展示出查询后的数据。这里我们的查询实现了两个小功能: 用户在输入某个字符后,自动在输入框下方用列表展示出用户可能要查询的词语(如用户名等) 同步更新表格中的数据 这里我们通过用户名和邮箱进行查询,因此在过滤数据时,需要检测用户名和邮箱是否含有查询的单词。我们先给输入框绑定一个input事件,同时用datalist展示用户可能要查询的词语: search功能的实现,searchlist为在输入框下方展示的可能要搜索的词语,ss数组则保存过滤后的数据,当循环完毕后,设置调用setSlist方法修改slist数组:// 搜索 search(e) { var v = e.target.value, self = this; self.searchlist = []; if (v) { var ss = []; // 过滤需要的数据 this.list.forEach(function (item) { // 检测用户名 if (item.username.indexOf(v) > -1) { if (self.searchlist.indexOf(item.username) == -1) { self.searchlist.push(item.username); } ss.push(item); } else if (item.email.indexOf(v) > -1) { // 检测邮箱 if (self.searchlist.indexOf(item.email) == -1) { self.searchlist.push(item.email); } ss.push(item); } }); this.setSlist(ss); // 将过滤后的数据给了slist } else { // 没有搜索内容,则展示全部数据 this.setSlist(this.list); } } 每当用户输入或者删除一个字符时都会调用search方法,执行查询操作,当用点击展示词语列表时,也会调用search方法。 5. 将弹层独立为组件 # 其实我们应该发现,修改功能(或新增功能)从代码和样式上相对来说比较独立,我们把弹层独立为组件的形式,把需要修改的数据通过props传递给该组件(新增数据时,可以给组件传递一个空数据),当用户点击保存时,再通过$emit给了父组件(子组件不能直接父级的数据,需要用data或者computed生成一个局部变量,然后再使用$emit方法把这个局部数据再传递上去):// 弹层组件 Vue.component('model', { props: ['list', 'isactive'], template: `新增 | 修改/* 省略 */`, computed: { modifylist() { return JSON.parse(JSON.stringify(this.list)); } }, methods: { changeActive() { this.$emit('change'); // 关闭弹层,修改isactive值 }, modify() { this.$emit('modify', this.modifylist); // 将修改后的数据传递给父组件 } } }); 父组件,在父组件中截取change和modify事件,再用changeOverlay和modify来实现: 6. 总结 # 洋洋洒洒写了不少,其实里面的难点不太多,主要是form表单方面的操作,再一个就是练习下组件间的数据与事件传递。内容比较简单,欢迎各位批评指正。
2024年10月21日
6 阅读
0 评论
0 点赞
2024-10-21
对博客进行了彻底的改造
在 coding 网站开始对静态博客收费后,各个第三方的评论系统也相继无法使用的情况下,于是就产生了对博客进行改造的想法。域名备案,购买服务器,把博客改造为 php 语言的,评论系统自己写,所有的数据都存储到数据库中。之前的博客是基于 jekyll 的静态博客,静态博客的好处就是,能全身心的写博客,而不用关注其他任何的配置。同时,在托管到 github 等一些网站上时,使用 git 就能直接 push 上去,不用 ftp 等工具上传。使用简单方便。可是,考虑到 github 有时候不稳定,coding 也不能免费使用了,使用的第三方评论系统(多说,网易云跟帖等)也相继关闭不能使用了。这时,就萌生了要把静态博客改造为基于 php 的博客系统。于是在下班的休息时间之余,在基本不改变博客外观的情况下,对博客进行里改造。 1. 网页的 DOM 结构更加清晰 # 之前的博客里,有很多无意义的标签,而且嵌套比较深。这些内容在新版里,都进行了改善 2. 静态资源按页面加载 # 之前的博客里,把所有的 css,js 都分别打包到一个文件里,每个页面加载这两个文件,导致加载了很多对该页面无意义的代码。新版的博客里,都是只加载当前页面需要的 css 和 js 3. 首页添加了分页 # 能在首页中通过分页查看到所有的博客文章 4. 实现基于微博登录的评论系统 # 第三方评论系统这么不靠谱,只能自己实现了 5. 添加相关文章推荐 # 基于当前文章的分类与标签,在文章底部推荐相似的 6 篇文章所有的数据都存储在数据库中后,我也实现了一个简单的后台管理系统,用来管理博客文章和评论。就目前而言,依然还有很多的东西需要完善,比如可以给文章添加一个点赞系统,比如后台的文章上传页还不支持 markdown 实时预览,等等。其实在实现这个博客系统时,当时考虑了不少的问题,比如,是否要自己实现一个 mvc 的方式来编写,当然,这个想法后来放弃了,改用 codeigniter 了;博客的评论内容是要同步加载,还是异步加载呢?后来考虑到两者的缓存时间不一样,文章可以长期缓存(没有大问题的情况基本不再更改),但是评论内容是随时都有可能更新的,于是就按照异步加载评论内容来实现了;是否要实现评论内容的邮件提醒,我想很多用户在你的网站评论后,也就离开了,其他用户对其内容的回复再也没有回应了,于是就添加了一个简单的邮件提醒,希望他能收到其他用户对他评论的回复;等等。下节,我们稍微讲解下,评论系统是如何实现的。
2024年10月21日
6 阅读
0 评论
0 点赞
1
...
24
25
26
...
213