首页

移动端、PC端 网页特效

前端达人

移动端网页特效

触屏事件

移动端浏览器兼容性较好,不需要考虑以前 JS 的兼容性问题,可以放心的使用原生 JS 书写效果,但是移动端也有自己独特的地方。比如触屏事件 touch(也称触摸事件),Android 和 IOS 都有。

touch 对象代表一个触摸点。触摸点可能是一根手指,也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。

常见的触屏事件:
在这里插入图片描述
触摸事件对象(TouchEvent)

TouchEvent 是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。这类事件用于描述一个或多个触点,使开发者可以检测触点的移动,触点的增加和减少,等等

touchstart、touchmove、touchend 三个事件都会各自有事件对象。

触摸事件对象常见对象列表:
在这里插入图片描述
因为平时都是给元素注册触摸事件,所以重点记住 targetTocuhes

移动端拖动元素JS代码实现:

// (1) 触摸元素 touchstart:  获取手指初始坐标,同时获得盒子原来的位置 // (2) 移动手指 touchmove:  计算手指的滑动距离,并且移动盒子 // (3) 离开手指 touchend: var div = document.querySelector('div'); var startX = 0; //获取手指初始坐标 var startY = 0; var x = 0; //获得盒子原来的位置 var y = 0; div.addEventListener('touchstart', function(e) { //  获取手指初始坐标 startX = e.targetTouches[0].pageX; startY = e.targetTouches[0].pageY; x = this.offsetLeft; y = this.offsetTop; }); div.addEventListener('touchmove', function(e) { //  计算手指的移动距离: 手指移动之后的坐标减去手指初始的坐标 var moveX = e.targetTouches[0].pageX - startX; var moveY = e.targetTouches[0].pageY - startY; // 移动我们的盒子 盒子原来的位置 + 手指移动的距离 this.style.left = x + moveX + 'px'; this.style.top = y + moveY + 'px'; e.preventDefault(); // 阻止屏幕滚动的默认行为 }); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

classList属性

classList属性是HTML5新增的一个属性。返回元素的类名,该属性用在元素中添加、移除及切换CSS类

<style> .bg { background-color: black; } </style> <body> <div class="one two"></div> <button> 开关灯</button> <script> // classList 返回元素的类名 var div = document.querySelector('div'); // console.log(div.classList[1]); // 1. 添加类名  是在后面追加类名不会覆盖以前的类名 注意前面不需要加. div.classList.add('three'); // 2. 删除类名 div.classList.remove('one'); // 3. 切换类 var btn = document.querySelector('button'); btn.addEventListener('click', function() { document.body.classList.toggle('bg'); }) </script> </body> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

常用开发插件

移动端 要求的是快速开发,所以经常会借助于一些插件来帮完成操作

JS 插件是 js 文件,它遵循一定规范编写,方便程序展示效果,拥有特定功能且方便调用。如轮播图和瀑布流插件

插件的使用:

  1. 引入 js 插件文件
  2. 按照规定语法使用

特点: 它一般是为了解决某个问题而专门存在,其功能单一,并且比较小。比如移动端常见插件:iScroll、Swiper、SuperSlider

PC端网页特效

偏移量系列 offset

offset 翻译过来就是偏移量, 使用 offset 系列相关属性可以 动态 的得到该元素的位置(偏移)、大小等。

  • 获得元素距离带有定位父元素的位置
  • 获得元素自身的大小(宽度高度)
  • 注意: 返回的数值都不带单位

常用属性:
在这里插入图片描述
图示:
在这里插入图片描述

offset与style区别:

offset style
可以得到任意样式表中的样式值 只能得到行内样式表中的样式值
offset系列获得的数值是没有单位的 style.width 获得的是带有单位的字符串
offsetWidth 包含padding+border+width style.width 获得不包含padding和border 的值
offsetWidth 等属性是只读属性,只能获取不能赋值 style.width 是可读写属性,可以获取也可以赋值
获取元素大小位置,用offset更合适 元素更改值,则需要用style改变

案例——获取鼠标在盒子内的坐标:

效果展示:
在这里插入图片描述

实现代码(JS):

// 在盒子内点击, 想要得到鼠标距离盒子左右的距离。 // 首先得到鼠标在页面中的坐标( e.pageX, e.pageY) // 其次得到盒子在页面中的距离(box.offsetLeft, box.offsetTop) // 用鼠标距离页面的坐标减去盒子在页面中的距离, 得到 鼠标在盒子内的坐标 var box = document.querySelector('.box'); box.addEventListener('mousemove', function(e) { // console.log(e.pageX); // console.log(e.pageY); // console.log(box.offsetLeft); var x = e.pageX - this.offsetLeft; var y = e.pageY - this.offsetTop; this.innerHTML = 'x坐标是' + x + ' y坐标是' + y; }) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

案例——模态拖拽框:

  • 点击弹出层, 会弹出模态框, 并且显示灰色半透明的遮挡层。
  • 点击关闭按钮,可以关闭模态框,并且同时关闭灰色半透明遮挡层。
  • 鼠标放到模态框最上面一行,可以按住鼠标拖拽模态框在页面中移动。
  • 鼠标松开,可以停止拖动模态框移动。

效果展示:
在这里插入图片描述

实现代码:

<head lang="en"> <meta charset="UTF-8"> <title></title> <style> .login-header { width: 100%; text-align: center; height: 30px; font-size: 24px; line-height: 30px; } ul,li,ol,dl,dt,dd,div,p,span,h1,h2,h3,h4,h5,h6,a { padding: 0px; margin: 0px; } .login { display: none; width: 512px; height: 280px; position: fixed; border: #ebebeb solid 1px; left: 50%; top: 50%; background: #ffffff; box-shadow: 0px 0px 20px #ddd; z-index: 9999; transform: translate(-50%, -50%); } .login-title { width: 100%; margin: 10px 0px 0px 0px; text-align: center; line-height: 40px; height: 40px; font-size: 18px; position: relative; cursor: move; } .login-input-content { margin-top: 20px; } .login-button { width: 50%; margin: 30px auto 0px auto; line-height: 40px; font-size: 14px; border: #ebebeb 1px solid; text-align: center; } .login-bg { display: none; width: 100%; height: 100%; position: fixed; top: 0px; left: 0px; background: rgba(0, 0, 0, .3); } a { text-decoration: none; color: #000000; } .login-button a { display: block; } .login-input input.list-input { float: left; line-height: 35px; height: 35px; width: 350px; border: #ebebeb 1px solid; text-indent: 5px; } .login-input { overflow: hidden; margin: 0px 0px 20px 0px; } .login-input label { float: left; width: 90px; padding-right: 10px; text-align: right; line-height: 35px; height: 35px; font-size: 14px; } .login-title span { position: absolute; font-size: 12px; right: -20px; top: -30px; background: #ffffff; border: #ebebeb solid 1px; width: 40px; height: 40px; border-radius: 20px; } </style> </head> <body> <div class="login-header"><a id="link" href="javascript:;">点击,弹出登录框</a></div> <div id="login" class="login"> <div id="title" class="login-title">登录会员 <span><a id="closeBtn" href="javascript:void(0);" class="close-login">关闭</a></span> </div> <div class="login-input-content"> <div class="login-input"> <label>用户名:</label> <input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="list-input"> </div> <div class="login-input"> <label>登录密码:</label> <input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="list-input"> </div> </div> <div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit">登录会员</a></div> </div> <!-- 遮盖层 --> <div id="bg" class="login-bg"></div> <script> // 1. 获取元素 var login = document.querySelector('.login'); var mask = document.querySelector('.login-bg'); var link = document.querySelector('#link'); var closeBtn = document.querySelector('#closeBtn'); var title = document.querySelector('#title'); // 2. 点击弹出层这个链接 link  让mask 和login 显示出来 link.addEventListener('click', function() { mask.style.display = 'block'; login.style.display = 'block'; }) // 3. 点击 closeBtn 就隐藏 mask 和 login  closeBtn.addEventListener('click', function() { mask.style.display = 'none'; login.style.display = 'none'; }) // 4. 开始拖拽 // (1) 当我们鼠标按下, 就获得鼠标在盒子内的坐标 title.addEventListener('mousedown', function(e) { var x = e.pageX - login.offsetLeft; var y = e.pageY - login.offsetTop; // (2) 鼠标移动的时候,把鼠标在页面中的坐标,减去 鼠标在盒子内的坐标就是模态框的left和top值 document.addEventListener('mousemove', move) function move(e) { login.style.left = e.pageX - x + 'px'; login.style.top = e.pageY - y + 'px'; } // (3) 鼠标弹起,就让鼠标移动事件移除 document.addEventListener('mouseup', function() { document.removeEventListener('mousemove', move); }) }) </script> </body> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168

可视区系列 client

client 翻译过来就是客户端,使用 client 系列的相关属性来获取元素可视区的相关信息。通过 client 系列的相关属性可以动态的得到该元素的边框大小、元素大小等。

常用属性:
在这里插入图片描述
client和offset最大的区别就是 :不包含边框
图示:
在这里插入图片描述

滚动系列 scroll

scroll 翻译过来就是滚动的,使用 scroll 系列的相关属性可以动态的得到该元素的大小、滚动距离等。

常用属性:
在这里插入图片描述
图示:
在这里插入图片描述

滚动条:

  • 如果浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条。
  • 当滚动条向下滚动时,页面上面被隐藏掉的高度,称为页面被卷去的头部。
  • 滚动条在滚动时会触发 onscroll 事件。

案例——固定右侧侧边栏:

  • 原先侧边栏是绝对定位
  • 当页面滚动到一定位置,侧边栏改为固定定位
  • 页面继续滚动,会让 返回顶部显示出来

效果展示:
在这里插入图片描述

实现代码:

<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .slider-bar { position: absolute; left: 50%; top: 300px; margin-left: 600px; width: 45px; height: 130px; background-color: pink; } .w { width: 1200px; margin: 10px auto; } .header { height: 150px; background-color: purple; } .banner { height: 250px; background-color: skyblue; } .main { height: 1000px; background-color: yellowgreen; } span { display: none; position: absolute; bottom: 0; } </style> </head> <body> <div class="slider-bar"> <span class="goBack">返回顶部</span> </div> <div class="header w">头部区域</div> <div class="banner w">banner区域</div> <div class="main w">主体部分</div> <script> //1. 获取元素 var sliderbar = document.querySelector('.slider-bar'); var banner = document.querySelector('.banner'); // banner.offestTop 就是被卷去头部的大小 一定要写到滚动的外面 var bannerTop = banner.offsetTop // 当侧边栏固定定位之后应该变化的数值 var sliderbarTop = sliderbar.offsetTop - bannerTop; // 获取main 主体元素 var main = document.querySelector('.main'); var goBack = document.querySelector('.goBack'); var mainTop = main.offsetTop; // 2. 页面滚动事件 scroll document.addEventListener('scroll', function() { // window.pageYOffset 页面被卷去的头部 // console.log(window.pageYOffset); // 3 .当页面被卷去的头部大于等于了 172 此时 侧边栏就要改为固定定位 if (window.pageYOffset >= bannerTop) { sliderbar.style.position = 'fixed'; sliderbar.style.top = sliderbarTop + 'px'; } else { sliderbar.style.position = 'absolute'; sliderbar.style.top = '300px'; } // 4. 当我们页面滚动到main盒子,就显示 goback模块 if (window.pageYOffset >= mainTop) { goBack.style.display = 'block'; } else { goBack.style.display = 'none'; } }) </script> </body> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

三大系列作用区别:
在这里插入图片描述

它们主要用法:

系列 作用 属性
offset 用于获得元素位置 offsetLeft offsetTop
client 用于获取元素大小 clientWidth clientHeight
scroll 用于获取滚动距离 scrollTop scrollLeft

注意:页面滚动的距离通过 window.pageXOffset 获得

动画原理

核心原理:通过定时器 setInterval() 不断移动盒子位置

实现步骤:

  1. 获得盒子当前位置
  2. 让盒子在当前位置加上1个移动距离
  3. 利用定时器不断重复这个操作
  4. 加一个结束定时器的条件
  5. 注意此元素需要添加定位,才能使用 element.style.left

简单动画函数封装:

// 简单动画函数封装obj目标对象 target 目标位置 function animate(obj, target) { var timer = setInterval(function() { if (obj.offsetLeft >= target) { // 停止动画 本质是停止定时器 clearInterval(timer); } //每次均匀向右移动1px obj.style.left = obj.offsetLeft + 1 + 'px'; }, 30); } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

缓动效果原理:

缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来

  1. 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来。
  2. 核心算法: (目标值 - 现在的位置 ) / 10 做为每次移动的距离步长
  3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
  4. 注意步长值需要取整
// 缓动动画函数封装obj目标对象 target 目标位置 // 思路: // 1. 让盒子每次移动的距离慢慢变小, 速度就会慢慢落下来。 // 2. 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长 // 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器 function animate(obj, target) { // 先清除以前的定时器,只保留当前的一个定时器执行 clearInterval(obj.timer); obj.timer = setInterval(function() { // 步长值写到定时器的里面 var step = (target - obj.offsetLeft) / 10; if (obj.offsetLeft == target) { // 停止动画 本质是停止定时器 clearInterval(obj.timer); } // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10 obj.style.left = obj.offsetLeft + step + 'px'; }, 15); } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

多个目标值之间移动:

当开始移动时候,判断步长是正值还是负值

  • 如果是正值,则步长 往大了取整
  • 如果是负值,则步长 向小了取整

动画函数封装到单独JS文件: animate.js

function animate(obj, target, callback) { // 先清除以前的定时器,只保留当前的一个定时器执行 clearInterval(obj.timer); obj.timer = setInterval(function() { // 步长值写到定时器的里面 // 把步长值改为整数 不要出现小数的问题 // var step = Math.ceil((target - obj.offsetLeft) / 10); var step = (target - obj.offsetLeft) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if (obj.offsetLeft == target) { // 停止动画 本质是停止定时器 clearInterval(obj.timer); // 回调函数写到定时器结束里面 // if (callback) { //     // 调用函数 //     callback(); // } callback && callback(); } // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10 obj.style.left = obj.offsetLeft + step + 'px'; }, 15); }

蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn 免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

vue 数据双向绑定原理

前端达人





首先我们为每个vue属性用Object.defineProperty()实现数据劫持,为每个属性分配一个订阅者集合的管理数组dep;然后在编译的时候在该属性的数组dep中添加订阅者,v-model会添加一个订阅者,{{}}也会,v-bind也会,只要用到该属性的指令理论上都会,接着为input会添加监听事件,修改值就会为该属性赋值,触发该属性的set方法,在set方法内通知订阅者数组dep,订阅者数组循环调用各订阅者的update方法更新视图。



一小段手写实现代码

仅供参考

class Vue {
constructor(option){
this.$data = option.data
Observe(this.$data)
Object.keys(this.$data).forEach((key)=>{
Object.defineProperty(this,key,{
enumerble: true,
configurable: true,
get(){
return this.$data[key]
},
set(newVal){
this.$data[key] = newVal
},
})
})
}
}

function Observe (obj){
if(!obj || typeof obj !== 'object') return
Object.keys(obj).forEach((key)=>{
let value = obj[key]
Observe(value)
Object.defineProperty(obj,key,{
enumerble: true,
configurable: true,
get(){
console.log('有人获取了 ${key} 的值')
return value
},
set(newVal){
value = newVal
Observe(value)
},
})
})
}

1

蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

使用 Nodemailer 发送邮件 邮件提醒通知功能实现

前端达人

Nodemailer 是一个基于Node的邮件服务模块。

使用 Nodemailer 完成一个发邮件功能非常简单,只需3步:

  1. 引入模块
  2. 创建 transport
  3. 发送邮件

引入模块

首先安装 Nodemailer

npm install nodemailer 

引入

var mailer = require('nodemailer'); 

创建transport

创建 transport 使用 Nodemailer 的createTransport方法,需要配置一下邮件服务。

首先,要在邮箱设置里开启 SMTP 服务。

然后,设置一个客户端授权密码。

最后,写一个配置文件(conf/mail.js)。以126邮箱为例:

module.exports = { host: 'smtp.126.com', auth: { user: 'user@126.com', pass: '******' } } 

host字段配置刚才开启的服务地址。
auth里的user字段配置邮箱账号,pass字段配置刚才设置的授权密码。

这样创建一个 transport:

var mailConf = require('conf/mail'); var transport = mailer.createTransport(mailConf); 

发送邮件

发邮件使用 Nodemailer 的sendMail方法,需要配置一下邮件内容。

这里配置了发件人,收件人,标题和正文:

var mailOptions = { from: mailConf.auth.user, to: 'receiver@xxx.com', subject: 'Hi, there', text: 'Mail from Node!' } 

可以像官方文档一样定义一个回调函数:

function mailCallback(error, info){ if(error){ return console.log(error); } console.log('Message sent: ' + info.response); } 

然后,就可以发送邮件了:

transport.sendMail(mailOptions, mailCallback); 

总结

这样就完成了最基本的发邮件功能。

Nodemailer 文档非常详细,可以探索实现更多功能。


蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:简书
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


JavaScript事件和修改this指向

前端达人

1、鼠标事件:

onclick 左键单击 ondblclick 左键双击 onmouseover onmouseenter 鼠标移入 onmouseout onmouseleave鼠标移出 onmousedown 鼠标按下 onmousmove 鼠标移动(鼠标滑动) onmouseup 鼠标抬起 oncontextmenu 右键单击(右键菜单)

 2、键盘事件:

onkeydown onkeypress 键按下 onkeyup 键抬起 键盘事件必须放在整个文档(document)里面去操作,不能放在节点里面去操作

3、系统事件:

onload 加载完成后 onerror 加载出错后 onresize 窗口调整大小时 onscroll 滚动时


  1. //onload 加载完成后 onerror 加载出错后 onresize 窗口调整大小时 都是放在window的身上
  2. window.onload = function(){};
  3. //onscroll 滚动时 可以放在document和window身上
  4. document.onscroll = function(){};

 4、表单事件:

onfocus 获取焦点后 onblur 失去焦点后 onchange 改变内容后 onreset 重置后 onselect 选择后 onsubmit 提交后

5、监听事件(绑定事件)写法:

节点.事件 = 函数

document.getElementById("main").onclick = function(){alert(1)};

document.getElementById("main").addEventListener("click",function(){},false);

行内绑定

<button οnclick="alert('hello world')">Click</button>

 <button οnclick="func()">Click</button>

<script type="text/javascript">

          var func = () => {

                    alert('hello world')

          };

</script>

6、事件函数this指向:在事件函数中,关键词 this 就表示触发事件的这个节点对象。

 7、修改this指向:

call() 第一个参数为 函数this将要修改指向的对象 函数有参数时 后面, 一一跟上即可 可以主动执行函数

apply() 第一个参数为 函数this将要修改指向的对象 函数有参数时 数组包一下 可以主动执行函数

bind() 第一个参数为 函数this将要修改指向的对象 函数有参数时 后面, 一一跟上即可 不不不会主动执行函数 但会return函数本体 再加一个括号即可执行  


  1. window.a = 0 //在window对象下创建一个属性,属性值为0
  2. let obj1 = {
  3. a: 1
  4. }
  5. let obj2 = {
  6. a: 2
  7. }
  8. function fn(num1, num2, num3) {
  9. console.log(this.a);
  10. console.log(num1, num2, num3);
  11. }
  12. //修改函数里面this的指向
  13. fn.call(obj1,4,5,6)
  14. fn.apply(obj2,[4,5,6])
  15. fn.bind(obj1,4,5,6)()

 


蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

Vue的双向数据绑定原理是什么?

前端达人

vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。 具体步骤: 第一步:需要

observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter,这样的 话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。 第二步:compile 解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对 应的节点绑定更新函数, 添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。 第三步:Watcher 订阅者是

Observer 和 Compile 之间通信的桥梁,主要做的事情是:

1、在自身实例化时往属 性订阅器(dep)里面添加自己

2、自身必须有一个 update()方法

3、待属性变动 dep.notice()通知时,能调用自身的update()方法,并触发 Compile 中绑定的回调,则功成身退。 第四步:MVVM 作为数据绑定的入口, 整合 Observer、Compile 和 Watcher 三者,通过 Observer 来监听自己 的 model 数据变化,通过Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和 Compile 之间的通信 桥梁,达到数据变化 -> 视图更新;视图交互变化(input)-> 数据 model 变更的双向绑定效果。









蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

SpringBoot与Vue交互解决跨域问题

前端达人

Hello,你好呀,我是灰小猿,一个超会写bug的程序猿!

最近在利用springboot+vue整合开发一个前后端分离的个人博客网站,所以这一篇总结一下在开发中遇到的一个问题,关于解决在使用vue和springboot在开发前后端分离的项目时,如何解决跨域问题。在这里分别分享两种方法,分别在前端vue中解决和在后台springboot中解决

浏览器同源策略

为什么会出现跨域问题? 首先一个定义一定要了解,就是浏览器的同源策略,

什么是浏览器的同源策略, 简单来说就是浏览器发送请求的协议、域名和端口要和服务器接收请求的协议、域名以及端口一致。这样才能完成交互,但是很显然这样是不可能的,尤其在对于在同一台电脑上开发前后端分离的项目的时候,一定是会使用两个端口的。那么这样就形成了跨域问题。

在这里分享一下我解决跨域问题用到的两个方法,

一、VUE前端配置代理解决跨域

(1)Vue中让浏览器请求携带cookie

先说一下我是怎么发现出现跨域问题的吧,最开始我在从前端浏览器向后台发送请求的时候是没有携带浏览器的cookie的,但是这样就导致了无法对浏览器的请求进行验证,所以在后来我用了一个方法让浏览器在每次发送请求的时候在http请求头中携带上cookie,方法如下:

在vue的main.js方法中写入如下代码:

//引入axios依赖 import axios from 'axios' //让请求携带上浏览器的cookie axios.defaults.withCredentials=true Vue.prototype.$axios = axios 
  • 1
  • 2
  • 3
  • 4
  • 5

以上表示引入axios请求,也就是ajax请求,同时开启写入凭证,只有withCredentials等于true的时候,才会携带cookie。

(2)vue中配置代理解决跨域

在vue中解决跨域问题其实也比较简单,因为我们每次浏览器发送的请求中,URL的前半部分一定是相同的,比如http://localhost:8080/blogs与http://localhost:8080/login,我们就可以将他们相同的URL提取出来,封装到axios.defaults.baseURL中,这样我们在每次请求的时候,就可以将请求地址简写成“/blogs”这样,也相当于是将URL头部进行了一个简单的封装。

注意:设置统一请求路径的axios.defaults.baseURL =
"http://localhost:8080"应该写在axios.js中

但是在解决跨域问题的时候,我们应该将axios.defaults.baseURL = "http://localhost:8080"写成axios.defaults.baseURL = “/api”。
这样我们每次请求的路径前面都会是“/api”的形式。
这也是第一步:

第一步,设置统一访问路径

在axios.js中设置axios.defaults.baseURL = "http://localhost:8080"写成axios.defaults.baseURL = "/api"

第二步、配置跨域代理

在babel.config.js的同级目录下新建一个js文件vue.config.js
在这里插入图片描述

在其中写入如下代码:这段代码是解决跨域问题而配置的一个代理。我这里后台服务器的请求连接是http://localhost:8081,所以如果你的不是的话需要修改一下。

/**
 * 解决跨域问题
 * @type {{devServer: {proxy: {"/api": {changeOrigin: boolean, pathRewrite: {"^/api": string}, target: string}}, host: string, open: boolean}}}
 */ module.exports = { devServer: { host: 'localhost', open: true, // 自动打开浏览器 // 代理配置表,在这里可以配置特定的请求代理到对应的API接口 // 例如将'localhost:8080/api/xxx'代理到'www.example.com/api/xxx' proxy: { '/api': { // 匹配所有以 '/api'开头的请求路径 target: 'http://localhost:8081', // 代理目标的基础路径 // secure: false,  // 如果是https接口,需要配置这个参数 changeOrigin: true, // 支持跨域 pathRewrite: { // 重写路径: 去掉路径中开头的'/api' '^/api': '' } } } } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

第三步、测试请求

如我们现在要发送login登录请求,那么请求应该是这样写的:

this.$axios.post("/login") 
  • 1

二、springboot后端配置解决跨域

在springboot框架的后端想要解决跨域问题,只需要添加一个类CorsConfig,并且让它实现WebMvcConfigurer接口, 其中代码如下,一般在开发的时候直接将代码复制过去就可以了。

 import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /**
 * 解决跨域问题
 */ @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS") .allowCredentials(true) .maxAge(3600) .allowedHeaders("*"); } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

以上我解决跨域的两种方法,在网上也查找了很多解决跨域的方法,但是错综复杂,经过尝试和自己研究,以上两种方法是我亲测成功的,当时前后端都配置了。

所以小伙伴们有不同的见解或者更好的方法,欢迎提出指正

我是灰小猿,我们下期见!











































蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

Vue 组件通信(父传子,子传父,跨组件传值)

前端达人

目录

一, 简单介绍组件通信

二, 详解传值方法

1.父传子 props

2.子传父 $emit

3.跨组件通信 event-bus


一, 简单介绍组件通信

        我们知道在现在的开发环境下,不管前后端开发都是组件化模块化,这是因为组件的优势无比的巨大,可以进行多次的复用增加开发效率,也可以分类鲜明,便于维护,而我今天所写的就是开发中分割成不同的组件互相传递数据和互动

        我的工作中常用地组件通信大致分为三类: 父传子 , 子传父 , 跨组件传值

        下面就来分别介绍一下 我常用的这三种传值方法

二, 详解传值方法

        父子组件的确认方法:我将 B 组件import引入到 A 组件中,那么 B 就是 A 的子组件,A 就是 B 的父组件

1.父传子 props

        简而言之,父传子就是父组件把数据传给子组件,具体就是如下,在子组件的props中定义自定义属性来待接收父组件的数据,有两种方法 如下:

        第一种,也是最推荐用的一种,以复杂类型的方式进行声明,这样存储的便是一个地址,可以和父组件的数据进行双向绑定,同步数据,虽然可以双向绑定,但是在Vue2.0中还是不可以直接在子组件中更改父组件的数据,需要用到子传父才行,这点等下会写到

        这里只是用 text 举个栗子,具体叫什么都可以哈,只是父子里面需要对应上相同

        这个 text 接收到数据后的使用方法和一般data中声明的变量一样,只是不能再子组件中改变他

子组件中:        props 定义属性接收

 
  1. <template>
  2. <div>
  3. <h2>son组件</h2>
  4. <p>props:{{ text }}</p>
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. // 在此处定义props
  10. props: {
  11. // props中定义 接收父组件数据的自定义属性,叫什么都可以,我随便起了个text
  12. text: {
  13. type: String, // type 是用来规定此属性接收到的数据的数据类型
  14. default: "未传递时默认的文字" // 这个default是当这个 text 没有接收到传递的数据时的默认值
  15. }
  16. }
  17. }
  18. </script>

父组件中:        标签内 传递数据

 
  1. <template>
  2. <div id="app">
  3. <!--
  4. 这里的text就是子组件props里定义的text,这两个名字得一致
  5. 并且传递的数据也要符合 type 规定的数据类型
  6. text就是传递字符串,:text就是传递动态数据
  7. -->
  8. <Son text="我是大娃 传给子啦" />
  9. <Son :text="wenzi" />
  10. </div>
  11. </template>
  12. <script>
  13. import Son from './components/son.vue';
  14. export default {
  15. data () {
  16. return {
  17. wenzi: '我是二娃 传给子啦'
  18. }
  19. },
  20. components: {
  21. Son
  22. }
  23. }
  24. </script>

        如上 虽然我的注释写的很清楚了,但是还是在介绍一下, <Son/> 是子组件的标签,在此标签的基础上书写 子组件props 定义的属性名,并且传递参数具体对应关系和效果如下:

        如上就是第一种我最常用的父传子,其实还有一种方法,但是我一般也不用,很不方便,也贴到下边了,这个是以数组方式声明

 
  1. export default {
  2. // 在此处定义props
  3. props: ['text']
  4. }
  5. </script>

 

2.子传父 $emit

        刚刚说到了在 Vue2.0 子组件不能直接改父组件的数据,否则会报错,这个解决方法就是在子组件中发起一个 自定义事件 ,在父组件监听这个事件,并且定义一个函数来改变数据,具体操作如下:

子组件:        发起一个自定义事件,等待父组件监听到执行函数

 
  1. <template>
  2. <div>
  3. <h2>son组件</h2>
  4. <p>props:{{ text }}</p>
  5. <button @click="changeTextFn">改变文字</button>
  6. </div>
  7. </template>
  8. <script>
  9. export default {
  10. // 在此处定义props
  11. props: {
  12. // props中定义 接收父组件数据的自定义属性,叫什么都可以,我随便起了个text
  13. text: {
  14. type: String, // type 是用来规定此属性接收到的数据的数据类型
  15. default: "未传递时默认的文字" // 这个default是当这个 text 没有接收到传递的数据时的默认值
  16. }
  17. },
  18. methods: {
  19. // 按钮点击事件
  20. changeTextFn () {
  21. // 发起自定义事件,名字叫什么都行,第一个参数是事件名,之后再跟着的都是传递的参数
  22. this.$emit('changeFn', '我想变成三娃')
  23. }
  24. }
  25. }
  26. </script>

        我先在原有的代码上添加了一个<button>按钮,在点击调用的函数中,通过 $emit 来发起事件并且可以传递参数

格式:        this.$emit('changeFn', '我想变成三娃') 

格式:        this.$emit('自定义事件名', 传递的参数) 

 

父组件:        行内监听子组件的 自定义事件名(函数上不用写参数,在 methods 中直接写形参就行)

 
  1. <template>
  2. <div id="app">
  3. <Son :text="wenzi" @changeFn="changeFn" />
  4. </div>
  5. </template>
  6. <script>
  7. import Son from './components/son.vue';
  8. export default {
  9. data () {
  10. return {
  11. wenzi: '我是二娃 传给子啦'
  12. }
  13. },
  14. components: {
  15. Son
  16. },
  17. methods: {
  18. // 监听子组件自定义事件
  19. changeFn (newText) {
  20. // 这里的形参接受到的就是子组件中 第二个参数传递的数值
  21. this.wenzi = newText
  22. }
  23. }
  24. }
  25. </script>

对应关系和效果图如下:

 

 

 

3.跨组件通信 event-bus

        如果两个组件的关系非常的复杂或者没有未产生直接联系,那么通过父子组件通讯是非常麻烦的。这时候可以使用通用的组件通讯方案:事件总线(event-bus)

        按照我的习惯,我会将事件总线创建到 main.js 中,这个使用原理是将bus挂载到Vue原型上,这样就可以保证所有的组件都能通过 this.bus 访问到事件总线,从而通过同一个事件总线监听同一个事件,具体原理和父子传参差不多,都是 $emit 传递数据, 只不过接收变成了$on 

        我这次以送礼物举例用了两个关系不大的组件 分别是 男组件 和 女组件 (随便起的名)具体如下图:

发送数据 男组件:   

    this.bus.$emit('自定义事件名',传递的参数) 

 
  1. <template>
  2. <div>
  3. <h1>男组件</h1>
  4. <button @click="sendGiftFn">送礼物</button>
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. data () {
  10. return {
  11. gift: '玫瑰花'
  12. }
  13. },
  14. methods: {
  15. sendGiftFn () {
  16. // 通过 bus 事件总线发起 自定义事件,并且传递参数(第一个是事件名,第二个开始是参数)
  17. this.bus.$emit('sendMessage', this.gift)
  18. }
  19. }
  20. }
  21. </script>

接收数据 女组件:         

 this.bus.$on('监听的事件名',(e)=>{ e这个形参所接收的就是监听事件所携带的参数数据 }) 

 
  1. <template>
  2. <div>
  3. <h1>女组件</h1>
  4. <p>来自男组件的礼物:{{ info }}</p>
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. data () {
  10. return {
  11. info: ""
  12. }
  13. },
  14. created () {
  15. // e 就是 sendMessage 这个事件所传递的数据
  16. this.bus.$on("sendMessage", (e) => {
  17. this.info = e;
  18. });
  19. }
  20. }
  21. </script>
  22. <style>
  23. </style>

具体效果如下:

 

综上所述,就是我在工作中总结出来的一些组建通信的方法,希望您看到这里会有所收获

蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

JavaScript作用域

前端达人

  • 作用域简介

  • JavaScript 作用域:就是代码名字,在某个范围内起的作用和效果。目的是为了提高程序的可靠性,减少命名冲突;

  • 作用域是可访问变量的集合。

  • 在 JavaScript 中, 对象和函数同样也是变量。

  • 在 JavaScript 中, 作用域为可访问变量,对象,函数的集合。

  • JavaScript 函数作用域: 作用域在函数内修改。

  •  变量的作用域:根据作用域的不同我们的变量可以分为全局变量和局部变量

  • 局部作用域

    
                        
    1. function fn() {
    2.     var str = '我是一个局部作用域';
    3. }
    4. console.log(str);    // 这时是访问不到的
    5. // 局部变量:在局部作用域下的变量   或者在函数内部的变量就是局部变量
    6. // 注意:函数的形参也可以看做是局部变量
    7. function fun(aru) {
    8.     var num1 = 50; // num1就是局部变量  只能在函数内部使用
    9.     console.log(num1); // 在这里使用是正确的 但是在函数外面使用报错
    10.     num2 = 70;
    11.     console.log(num2); // num2在这里可以正常输出
    12.     console.log(aru);
    13.     // 首先在fun括号里面传入一个hello 然后在函数内部输出是正确的但是在函数外部输出是错误的
    14. }
    15. //fun(); 
    16. fun('hello');
    17. //console.log(num1);// 报错 num1是局部变量
    18. console.log(num2); // 这里可以输出num2是因为num2是特殊的全局变量
  • 全局作用域:

    全局变量:在全局作用域下的变量称为全局变量,在全局下都可以使用
    // 注意:如果在函数内部没有声明直接赋值的变量也属于全局变量
     

    
                        
    1. var num = 10; //num就是一个全局变量
    2. console.log(num);
    3. function fn() {
    4.     console.log('全局变量在函数内部也可以使用' + num);
    5. }
    6. fn();
  • 作用域链

  • 作用域链:内部函数访问外部函数的变量,采取的是链式查找的方式决定取哪个值 这种结构我们称为作用域链 就近原则

  • 
                        
    1. var num = 10;
    2. function fn() { //外部函数
    3.     var num = 20;
    4.     function fun() { //内部函数
    5.         console.log(num);
    6.     }
    7.     fun();
    8. }
    9. fn();
  • 作用域链总结:

  • 内部函数访问外部函数的时候,采取的是链式查找的方式,一层一层往外查找

  • 先是查找外一层,有没有,没有在往外接着查找,找到了我就输出相应的结果

  • 没有的话继续往上找就可以了,所以这个方法,我们称为作用域链

  • 简单总结就是就近原则,谁离我近我就执行谁


蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

前端脚手架的执行原理

前端达人

最近收到几位老师留言,提到一些脚手架相关的问题,跟着自己浅显的理解,以vue脚手架在windows系统上的执行为例做个分析。

正题之前,先说几个概念

脚手架的本质:运行在操作系统上node客户端里的可执行程序。

脚手架做了哪些工作?一般脚手架的工作内容主要包括三方面:

  1. 创建项目+通用代码: 埋点、http请求、工具方法、组件库。
  2. git操作: 创建仓库、代码冲突、远程代码同步、创建版本、发布打tag。
  3. 构建+发布上线: 依赖安装和构建、资源上传CDN、域名绑定、测试\正是服务器。

脚手架给我们带来哪些好处?提升前端研发效能!(就这么一句空话~~)从其为我们带来的最终体验上来讲,是实现研发过程的:

  1. 自动化:项目重复代码的copy、git操作、发布上线操作;
  2. 标准化:项目创建、git flow、发布流程、回滚流程;
  3. 数据化:使研发过程系统化、数据化、使得研发过程可量化。

脚手架的命令执行

vue create csjName –g
  1. vue 是脚手架名称
  2. create 是command,脚手架中已注册的命令
  3. csjName 是params,命令的参数
  4. –g 是options,命令的配置
  5. 一般options后也会有参数,我们称之为配置参数,上面命令其实是省略了true
    vue create csjName –g true

下面说一下vue脚手架的执行过程

环境要求,已安装node

先来思考一个问题:

我们安装vue脚手架时,安装的是@vue/cli

npm install @vue/cli –g

为什么创建项目的时候用的却是vue

vue create projectName

咱们先看 npm install @vue/cli –g命令完成拉资源后,在操作系统中都做了什么。

命令执行完成后,咱们切换到D:\mysoft\node\node_global(这个是自己安装node时设置的全局npm包的安装路径,并且已配置到环境变量中,不清楚的老师可以去熟悉一下node的安装教程),发现此路径下已经生成了一个cmd命令vue.cmd,因为此路径已配置到环境变量中,所以在cmd我们必然可以直接输入vue来执行vue.cmd。

那么vue.cmd文件中又执行了什么?打开vue.cmd

可以看到,其实它是去调用了vue脚手架资源路径下的vue.js文件

正如我们在这个路径下执行

node vue.js create csjName

是一样的。脚手架的命令及其参数的注册与解析都在此文件中完成。具体的代码逻辑不再深入讲了,因为我也没看。。。。。

再来思考个问题,在完成脚手架资源的下载后,为什么会在D:\mysoft\node\node_global下自动生成一个vue.cmd?我们能不能自定义这个脚手架的名字?

其实每个脚手架都是npm项目,vue.cmd是在此npm项目的package.json中配置的,我们也可以对其自定义修改。

欲修改脚手架名称,直接去D:\mysoft\node\node_global下重命名vue.cmd即可。如果是自己的脚手架,可在npm项目内的package.json中通过上述配置,指定脚手架的名称。

补充

另外在linux或mac系统中,其实node\node_global下并未生成vue.cmd,而是生成了一个叫做vue软链接,并且链向了node_global\node_modules\@vue\cli下的vue.js。

而且在linux和mac系统中,并未使用node vue.js,而是直接执行了vue.js那是因为在vue.js顶部已通过Shebang声明当前文件默认使用系统中环境变量/usr/bin/env 下的node解释器执行。此语法在windows系统中无效。

以上是对vue脚手架在windows中执行过程的浅显理解。不到之处,还请指正~~

最后安利一个自己已发布的npm项目csjtools,旨在打造一个前端通用的工具库,就是自己平常封装的js工具函数,如对timeout的异步封装、对storage的面向对象的封装、对日期格式的转换、还有对象之间的深比较等,目前工具还不够丰富,欢迎大家一起使用&完善,一个人的力量很小~~

npm install csjtools -g 


蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

Vue的防抖和节流(接口频繁调用如何处理)

前端达人

首先描述一下我所使用的业务场景:系统有一个批量审批的功能,每个审批的流程需要根据提交的用户实时的反馈回去进去用户页面的刷新,如果一个用户同时有多个流程被审批通过,前端会向服务端频繁的多次调用同一个接口,造成服务器压力过大和页面卡顿,非常影响用户体验。
目标:需要短时间内向服务端频繁调用接口时只去调用最后一次的接口。(防抖)

防抖和节流的区别:主要体现在执行次数上的区别,比如我们写一个200ms的延迟时间,节流就是每200ms执行一次,而抖动是只有在最后一次事件的200ms内调用一次回调函数。
防抖和节流都可以用于 mousemove、scroll、resize、input、click等事件,他们的区别在于防抖只会在连续的事件周期结束时执行一次,而节流会在事件周期内按间隔时间有规律的执行多次。

防抖 debounce

当事件被频繁触发时,在一定的时间内再去执行回调函数,如果在等待期间再次被触发,则重新计时,直至整个等待期间没有新的事件被触发,执行回调函数。

举个例子:一个点击事件,为了防止用户重复发起请求,如果用户在三秒内多次发生点击事件,点击事件将只执行一次,第一次和第二次点击的间隔只要在三秒钟内就会重置这个等待时间,第二次和第三次之间的最大等待时间也是三秒,如果第二次点击事件发生后的三秒内没有新的点击事件产生,第二次点击后的三秒就会调用回调函数。

可以直接引用loadsh的debounce方法来实现函数防抖,也可以自己写一个防抖函数(利用定时器)

  1. 引用loadsh

这里先给一个中文文档的地址:https://www.lodashjs.com/docs/lodash.debounce
在vue3.x中也推荐了这种方式:https://v3.vuejs.org/guide/data-methods.html#methods
有多种引用方式,这里我直接采用npm的方式

npm i --save lodash 
  • 1

使用loadsh的debounce方法

<el-button id="myBtn" type="goon" icon="el-icon-search" @click="test">点击事件</el-button> 
  • 1
let _ = require('lodash'); _.debounce(fun,ms,options) fun: 回调函数
ms:等待时间,毫秒
options:选项对象 
  • 1
  • 2
  • 3
  • 4
  • 5

注意:这里点击事件要写成test: 的形式,test()这样是不生效的

import debounce from 'lodash/debounce' methods:{ test:debounce(()=>{ console.log("防抖函数执行",) },3000) } //或者下面这种写法 document.getElementById("myBtn").addEventListener('click', debounce(function (event) { console.log("防抖函数执行",) }, 3000)) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  1. 自定义防抖函数
<el-button type="goon" icon="el-icon-search" @click="test">点击事件</el-button> 
  • 1
data:{ timer:null }, methods:{ //在最后一次点击三秒后才会触发一次点击事件 test(){ clearTimeout(this.timer) //自定义个定时器三秒后执行,一旦有新的事件发生会将这个定时器清除重新创建一个,只有三秒内不出现事件这个定时器才不会被销毁重构 this.timer = setTimeout(()=>{ console.log("防抖执行,这里就是你需要执行的操作") },3000) } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

节流 throttle

在规定的时间内只触发一次回调函数,在规定时间内多次触发函数,只会执行一次

举个例子:一个点击事件,你设定了节流的延迟时间为一秒钟,那么在你一直点击的情况下,每隔一秒会触发一次这个事件,直到你的点击停止,这个不会累积,比如一秒钟内点击了五次,然后不再点击时,事件也只会触发一次而不会累积到触发五次,这种累积的可以采用定时器实现。

节流一般多用于监听输入框和滚动条,同样的在我们的loadsh中也有写好的节流的函数throttle,使用方法和上面防抖类似,这里就不详细写了,主要写一下 自定义的节流函数。

throttle(fun, ms,options) fun:需要节流的回调函数
ms:等待时间
options:额外配置项 
  • 1
  • 2
  • 3
  • 4

自定义节流函数:
原理就是用时间戳判断是否到了回调的执行时间,记录上次执行的时间戳,然后每次触发 事件执行回调,回调里边判断当前时间戳距离上一次执行时间戳的间隔是否已经到达规定的时间,如果是就执行,并且会更新上次执行的时间戳。
下面是我写的一个简单的例子,可以根据自己需求进行修改

data:{ //这里我直接页面创建时定义了一个初始的变量,保存上一次函数执行的时间 lastTime:new Date() }, methods:{ //fun 代表要执行的函数,需要被节流的函数 throttle(fun){ //函数执行时的时间 let now = new Date() console.log("now",now) console.log("lastTime",this.lastTime) //两次调用的时间差 if (now - this.lastTime > 1000){ fun() //调用成功,上一次调用时间值修改 this.lastTime = now } }, test(){ this.throttle(function (){ //1000ms内无论点击多少下,只会调用一次 console.log("节流函数调用,时间1000ms") }) }, } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

image.png

如果项目多次用到可以将以上的方法封装成一个工具类。

参考文章:https://www.jb51.net/article/161713.htm














蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档