首页

JavaScript制作贪吃蛇小游戏

前端达人

目录

效果展示

原理分析

 Game.js文档

Snake.js文档

Food.js文档

附上源代码


写了这么久的代码

是否你和我一样感到枯燥乏味了呢?

是否没有前进的动力了呢?

别忘了当时的你踌躇满志将前端Web一举拿下的斗志啊!


今天博主要给大家展现一个好玩的游戏

贪吃蛇小游戏!

嘿,你可别小瞧这东西!

制作过程是从无到有

等做完它

你就能从中体会到比玩游戏还快乐的居然是打代码!


效果展示

原理分析

我们制作前为了代码更清晰就分成几个js文档来编写。

其中Game.js可以看作是一个媒介的作用;Snake.js是当蛇初始化时在最左边向右走的状态;

 贪吃蛇在游戏中的运动可以想象成这条蛇是在一张25*25的表格中运动:

 如图所示

 Game.js文档

所以我们在Game.js中添加表格节点

 
  1. function Game() {
  2. this.row = 25;
  3. this.col = 25;
  4. }
  5. Game.prototype.init = function() {
  6. this.dom = document.createElement('table');
  7. // 创建表格--父元素为document(页面中创建表格)
  8. // var tr, td;
  9. for (var i = 0; i < this.row; i++) { //追加行
  10. var tr = document.createElement('tr');
  11. for (var j = 0; j < this.td; j++) { //追加列
  12. var td = document.createElement('col');
  13. td.appendChild(tr);
  14. }
  15. }
  16. };

Snake.js文档






Snake.js中当蛇初始化时最左边向右走的状态

如图所示

 
  1. function Snake() {
  2. // 蛇的初始化身体
  3. this.body = [
  4. { 'row': 3, 'col': 5 },
  5. { 'row': 3, 'col': 4 },
  6. { 'row': 3, 'col': 3 },
  7. { 'row': 3, 'col': 2 }
  8. ];
  9. }
  10. Snake.prototype.render = function() {
  11. // 蛇头的渲染
  12. game.setColorHead(this.body[0].row, this.body[0].col.'pink');
  13. // 蛇身的渲染
  14. for (var i = 1; i < this.body.length; i++) {
  15. game.setColor(this.body[i].row, this.body[i].col, 'cyan')
  16. }
  17. }

蛇在运动的时候它的原理是“头增尾删”。

因为蛇的长度先是不变的,而我们改变的也是改变这个四个格子的颜色,走一格头部那一格颜色变为粉色,尾巴那一格的颜色变为白色。


接下来让蛇通过我们按键来进行运动:放在一个监听事件内

 
  1. // 设置键盘的事件监听
  2. Game.prototype.bindEvent = function() {
  3. var self = this;
  4. document.addEventListener('keydown', function(e) {
  5. // 用ASCII码值判断键盘方向
  6. switch (e.keyCode) {
  7. case 37: //左
  8. if (self.snake.direction == 'R') return; // 先进行判断,如果当前的方向是向右移动,此时我们不能按左键
  9. self.snake.changeDirection('L');
  10. self.d = 'L';
  11. break;
  12. case 38: //上
  13. if (self.snake.direction == 'D') return; // 先进行判断,如果当前的方向是向下移动,此时我们不能按上键
  14. self.snake.changeDirection('U');
  15. self.d = 'U';
  16. break;
  17. case 39: //右
  18. if (self.snake.direction == 'L') return; // 先进行判断,如果当前的方向是向左移动,此时我们不能按右键
  19. self.snake.changeDirection('R');
  20. self.d = 'R';
  21. break;
  22. case 40: //下
  23. if (self.snake.direction == 'U') return; // 先进行判断,如果当前的方向是向上移动,此时我们不能按下键
  24. self.snake.changeDirection('D');
  25. self.d = 'D';
  26. break;
  27. }
  28. })
  29. }

接下来我们判定蛇是否撞到墙而结束

 
  1. // 死亡的判断,超出了表格边缘的部分
  2. if (this.body[0].col > game.col - 1 || this.body[0].col < 0 || this.body[0].row > game.row - 1 || this.body[0].row < 0) {
  3. alert('撞到墙了哦,一共吃掉了' + game.score + '颗草莓');
  4. this.body.shift();
  5. clearInterval(game.timer);
  6. location.reload();
  7. }


接下来我们判定蛇是否撞到自己而结束

 
  1. // 自己撞到自己的时候会判定死亡
  2. for (var i = 1; i < this.body.length; i++) {
  3. // 如果当前蛇的头部和身体的某一个部位的 row 和 col 完全重合的时候
  4. if (this.body[0].row == this.body[i].row && this.body[0].col == this.body[i].col) {
  5. alert('撞到自己了,吃掉了' + game.score + '颗草莓');
  6. this.body.shift();
  7. clearInterval(game.timer);
  8. location.reload();
  9. }
  10. }

Food.js文档


食物food类,用来产生食物

 
  1. function Food(gameSnake) {
  2. // 食物的位置
  3. this.row = parseInt(Math.random() * gameSnake.row)
  4. this.col = parseInt(Math.random() * gameSnake.col)
  5. }
  6. Food.prototype.render = function() {
  7. game.setHTML(this.row, this.col);
  8. }

食物随机生成在单元格中,利用do...while来实现

 
  1. function Food(gameSnake) {
  2. var self = this;
  3. // 下面的 do-while 循环语句作用是先创建一个 row 和 col
  4. 然后判断这个 row 和 col 是否在蛇的身上
  5. //do...while来创建食物
  6. do {
  7. // 食物的位置
  8. this.row = parseInt(Math.random() * gameSnake.row)
  9. this.col = parseInt(Math.random() * gameSnake.col)
  10. } while ((function() {
  11. // 遍历蛇的 row col 然后和 food 新随机出来的 row col 进行判断,是否重合
  12. for (var i = 0; i < gameSnake.snake.body.length; i++) {
  13. if (self.row == gameSnake.snake.body[i].row && self.col == gameSnake.snake.body[i].col) {
  14. return true;
  15. }
  16. }
  17. return false;
  18. })());
  19. }

文章来源:csdn   作者:

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

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

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



Vue按需引入Echarts,并从V4版本升级到V5版本

前端达人

一、原本的V4版本按需引入: main.js页面

import Echarts from 'echarts/lib/echarts' import 'echarts/lib/chart/pie' import 'echarts/lib/chart/bar' import 'echarts/lib/chart/line' Vue.prototype.echarts = Echarts 
  • 1
  • 2
  • 3
  • 4
  • 5

二、升级版本

!!!注意:要先删除插件,再重新安装插件,要不然是没效果的(我就说咋没效果)

  • 删除echarts
npm uninstall echarts --save 
  • 1
  • 再重新安装echarts
npm install echarts --save 
  • 1

三、按需处理

  • 在main.js页面

参考官方:https://echarts.apache.org/zh/tutorial.html#%E5%9C%A8%E6%89%93%E5%8C%85%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8%20ECharts

import * as Echarts from 'echarts/core'; import { BarChart, PieChart, LineChart } from 'echarts/charts'; import { TitleComponent, TooltipComponent, GridComponent, LegendComponent } from 'echarts/components'; // 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步 import { CanvasRenderer } from 'echarts/renderers'; Echarts.use([BarChart, PieChart, LineChart, TitleComponent, TooltipComponent, GridComponent, CanvasRenderer, LegendComponent]) Vue.prototype.echarts = Echarts 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

四、成功




文章来源:csdn   作者:

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

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

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

几个超火的在线编程网站,别错过

前端达人

大家好,我是鱼皮,今天给大家推荐几个最近非常流行的编程网站,相信能够帮助大家提高编程效率、更好地学习编程。

热门编程网站推荐

Codepen

演示视频:https://www.bilibili.com/video/BV1im4y1X7zb/

国外的在线前端编程网站,在这里你可以发现很多国外大神编写的前端代码,除了各种网页布局代码外,更多的是各式各样好玩的、炫酷的、新颖的前端动画和特效。

比如圣诞节快到了,很多小伙伴问我能不能用代码画颗圣诞树。

我是不会,但是在这个网站中,输入 “Christmas Tree” 搜索,就能看到各种不同风格的圣诞树网页啦!

Codepen 好玩的网页

点击你看中的网页,就能进到代码编辑页面,在这里,你可以任意修改 HTML、CSS、JavaScript 前端代码,并且在底部的区域实时浏览运行效果,非常地方便!

在线编辑

编辑好网页后,可以在网页右下角的菜单中进行全屏浏览、收藏、克隆、分享等,还能直接将网页内嵌到我们自己的项目中,或者下载完整代码包到本地。

网页操作

得益于前端技术的发展,这个网站为开发者提供了搜索项目、在线编辑、分享导出的一条龙服务,使得我们能够以自主练习的方式轻松学习别人优秀的代码。

下面再分享几个类似的网站。

CodeSandbox

代码沙箱,顾名思义,可以帮助你在隔离的环境中运行前端项目。

在这里你可以基于丰富的模板来创建自己的沙箱(项目),比如 React、Vue、Angular、VuePress、Svelte 等常见的前端框架:

创建好沙箱后,你就可以在线编辑代码、实时查看效果,或者分享沙箱给其他小伙伴啦~

在线编辑

JSFiddle

前端开发的练习场,也可以在线编写代码、实时浏览效果。相对于 Codepen,个人感觉这个网站的编辑体验更好:

在线编辑

当你在网上看到了一段不错的 JS 代码或者插件,不必再下载到本地了。直接把代码粘贴到 JSFiddle 中,就能以最快的方式查看运行效果了。现在很多前端组件库也用到了这种平台,给开发者所见即所得的体验。

JSRUN

国内的在线编程网站,除了前端外,甚至支持多达 30 多种编程语言的在线调试和运行!

同 Codepen 一样,你可以在这里看到很多别人编写的代码片段,直接下载。还可以保存和分享你的代码,建立自己的小代码合集。

下载代码

不得不说,在国内,这个网站算是做的相当出色的了,访问速度和功能体验都很棒!

Gitpod

这个平台要比上面提到的网站更高级一些,它是一个强大的在线 IDE(集成编程环境),提供了 VSCode 风格的编辑器,允许你在线编写代码完成开发。

在线 IDE

Gitpod 基于容器技术,可以帮助你一键编译、构建、运行任何 GitHub 项目,不止前端!而且每个项目的运行都是互相隔离的,随用随创建、用完可随时回收,非常灵活。

如果你看中了一个 GitHub 项目,又不想在本地去搭建各种环境去查看它的运行效果,那么最好的方式就是使用 Gitpod 来在线构建和执行。现在也有越来越多的 GitHub 项目接入了 Gitpod,大家只要看到下图的按钮,都是可以一键部署运行的,大大提高效率!


以上就是本期分享,有帮助的话帮忙点个  吧,谢谢大家!


文章来源:csdn   作者:

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

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

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

代码写春联【js+html版本与python版本】

前端达人

文章来源:人人都是产品经理   作者:新榜

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

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

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

一、春联一

1.前言

需要代码文末公众号找我 回复【春联】即可获取
在这里插入图片描述

效果展示

在这里插入图片描述

3.代码展示

index.html

<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <title>css3春联切换</title> <link rel="stylesheet" href="css/style.css"> </head> <body> <div class="rotating-text"> <p>春联Show</p> <p> <span class="word alizarin">上联:这个需求很简单</span> <span class="word wisteria">下联:怎么实现我不管</span> <span class="word peter-river">横批:明天上线!</span> </p> </div> <script src="js/script.js"></script> </body> </html>  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

style.css

@import url(https://fonts.googleapis.com/css?family=Lato:600); body { display: flex; justify-content: center; align-items: center; height: 100vh; background: #222; } .rotating-text { font-family: Lato, sans-serif; font-weight: 600; font-size: 36px; color: white; transform: translateX(-80px); } .rotating-text p { display: inline-flex; margin: 0; vertical-align: top; } .rotating-text p .word { position: absolute; display: flex; opacity: 0; } .rotating-text p .word .letter { transform-origin: center center 25px; } .rotating-text p .word .letter.out { transform: rotateX(90deg); transition: 0.32s cubic-bezier(0.6, 0, 0.7, 0.2); } .rotating-text p .word .letter.in { transition: 0.38s ease; } .rotating-text p .word .letter.behind { transform: rotateX(-90deg); } .alizarin { color: #e74c3c; } .wisteria { color: #8e44ad; } .peter-river { color: #3498db; } .emerald { color: #2ecc71; } .sun-flower { color: #f1c40f; }  
  • 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

script.js

var words = document.querySelectorAll(".word"); words.forEach(function (word) { var letters = word.textContent.split(""); word.textContent = ""; letters.forEach(function (letter) { var span = document.createElement("span"); span.textContent = letter; span.className = "letter"; word.append(span); }); }); var currentWordIndex = 0; var maxWordIndex = words.length - 1; words[currentWordIndex].style.opacity = "1"; var rotateText = function () { var currentWord = words[currentWordIndex]; var nextWord = currentWordIndex === maxWordIndex ? words[0] : words[currentWordIndex + 1]; // rotate out letters of current word Array.from(currentWord.children).forEach(function (letter, i) { setTimeout(function () { letter.className = "letter out"; }, i * 80); }); // reveal and rotate in letters of next word nextWord.style.opacity = "1"; Array.from(nextWord.children).forEach(function (letter, i) { letter.className = "letter behind"; setTimeout(function () { letter.className = "letter in"; }, 340 + i * 80); }); currentWordIndex = currentWordIndex === maxWordIndex ? 0 : currentWordIndex + 1; }; rotateText(); setInterval(rotateText, 4000);  
  • 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

二、春联二

1.环境准备

1.当缺少库时会有相应提示 黑窗口执行下方命令+包名即可下载安装
2.博主此处用的idea 直接Alt+Enter直接下载就成了
3.idea配置python环境也可以参考此文:Python(含PyCharm及配置)下载安装以及简单使用(Idea)

2.效果展示

在这里插入图片描述
在这里插入图片描述

3.代码

import io from PIL import Image #import numpy as np import requests def get_word(ch, quality): """获取单个汉字(字符)的图片
    ch          - 单个汉字或英文字母(仅支持大写)
    quality     - 单字分辨率,H-640像素,M-480像素,L-320像素
    """ fp = io.BytesIO(requests.post(url='http://xufive.sdysit.com/tk', data={'ch': ch}).content) im = Image.open(fp) w, h = im.size if quality == 'M': w, h = int(w * 0.75), int(0.75 * h) elif quality == 'L': w, h = int(w * 0.5), int(0.5 * h) return im.resize((w, h)) def get_bg(quality): """获取春联背景的图片""" return get_word('bg', quality) def write_couplets(text, HorV='V', quality='L', out_file=None): """生成春联

    text        - 春联内容,以空格断行
    HorV        - H-横排,V-竖排
    quality     - 单字分辨率,H-640像素,M-480像素,L-320像素
    out_file    - 输出文件名
    """ usize = {'H': (640, 23), 'M': (480, 18), 'L': (320, 12)} bg_im = get_bg(quality) text_list = [list(item) for item in text.split()] rows = len(text_list) cols = max([len(item) for item in text_list]) if HorV == 'V': ow, oh = 40 + rows * usize[quality][0] + (rows - 1) * 10, 40 + cols * usize[quality][0] else: ow, oh = 40 + cols * usize[quality][0], 40 + rows * usize[quality][0] + (rows - 1) * 10 out_im = Image.new('RGBA', (ow, oh), '#f0f0f0') for row in range(rows): if HorV == 'V': row_im = Image.new('RGBA', (usize[quality][0], cols * usize[quality][0]), 'white') offset = (ow - (usize[quality][0] + 10) * (row + 1) - 10, 20) else: row_im = Image.new('RGBA', (cols * usize[quality][0], usize[quality][0]), 'white') offset = (20, 20 + (usize[quality][0] + 10) * row) for col, ch in enumerate(text_list[row]): if HorV == 'V': pos = (0, col * usize[quality][0]) else: pos = (col * usize[quality][0], 0) ch_im = get_word(ch, quality) row_im.paste(bg_im, pos) row_im.paste(ch_im, (pos[0] + usize[quality][1], pos[1] + usize[quality][1]), mask=ch_im) out_im.paste(row_im, offset) if out_file: out_im.convert('RGB').save(out_file) out_im.show() text = '思前想后几行代码筑万载春秋 扶内保外一千精英带五千干将' #对联内容 write_couplets(text, HorV='V', quality='M', out_file='春联.jpg') #生成普天同庆.jpg对联图片  
            
  • 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
白哥Java
微信公众号
获取Java面试资料/简历模板/项目资料
3.代码

import io from PIL import Image #import numpy as np import requests def get_word(ch, quality): """获取单个汉字(字符)的图片 ch - 单个汉字或英文字母(仅支持大写) quality - 单字分辨率,H-640像素,M-480像素,L-320像素 """ fp = io.BytesIO(requests.post(url='http://xufive.sdysit.com/tk', data={'ch': ch}).content) im = Image.open(fp) w, h = im.size if quality == 'M': w, h = int(w * 0.75), int(0.75 * h) elif quality == 'L': w, h = int(w * 0.5), int(0.5 * h) return im.resize((w, h)) def get_bg(quality): """获取春联背景的图片""" return get_word('bg', quality) def write_couplets(text, HorV='V', quality='L', out_file=None): """生成春联 text - 春联内容,以空格断行 HorV - H-横排,V-竖排 quality - 单字分辨率,H-640像素,M-480像素,L-320像素 out_file - 输出文件名 """ usize = {'H': (640, 23), 'M': (480, 18), 'L': (320, 12)} bg_im = get_bg(quality) text_list = [list(item) for item in text.split()] rows = len(text_list) cols = max([len(item) for item in text_list]) if HorV == 'V': ow, oh = 40 + rows * usize[quality][0] + (rows - 1) * 10, 40 + cols * usize[quality][0] else: ow, oh = 40 + cols * usize[quality][0], 40 + rows * usize[quality][0] + (rows - 1) * 10 out_im = Image.new('RGBA', (ow, oh), '#f0f0f0') for row in range(rows): if HorV == 'V': row_im = Image.new('RGBA', (usize[quality][0], cols * usize[quality][0]), 'white') offset = (ow - (usize[quality][0] + 10) * (row + 1) - 10, 20) else: row_im = Image.new('RGBA', (cols * usize[quality][0], usize[quality][0]), 'white') offset = (20, 20 + (usize[quality][0] + 10) * row) for col, ch in enumerate(text_list[row]): if HorV == 'V': pos = (0, col * usize[quality][0]) else: pos = (col * usize[quality][0], 0) ch_im = get_word(ch, quality) row_im.paste(bg_im, pos) row_im.paste(ch_im, (pos[0] + usize[quality][1], pos[1] + usize[quality][1]), mask=ch_im) out_im.paste(row_im, offset) if out_file: out_im.convert('RGB').save(out_file) out_im.show() text = '思前想后几行代码筑万载春秋 扶内保外一千精英带五千干将' #对联内容 write_couplets(text, HorV='V', quality='M', out_file='春联.jpg') #生成普天同庆.jpg对联图片
 


11

222

文章来源:csdn  作者: 分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务

JavaScript——异步操作以及Promise 的使用

前端达人

什么是异步?

异步与同步是相反的

简单来理解就是:同步按你的代码顺序执行,异步不按照代码顺序执行,异步的执行效率更高。

什么时候用异步编程

在前端编程中(甚至后端有时也是这样),我们在处理一些简短、快速的操作时,例如计算 1 + 1 的结果,往往在主线程中就可以完成。主线程作为一个线程,不能够同时接受多方面的请求。所以,当一个事件没有结束时,界面将无法处理其他请求。

现在有一个按钮,如果我们设置它的 onclick 事件为一个死循环,那么当这个按钮按下,整个网页将失去响应。

为了解决类似这种问题,JavaScript 中的异步操作函数往往通过回调函数来实现异步任务的结果处理。

回调函数

回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么。这样一来主线程几乎不用关心异步任务的状态了,他自己会善始善终。

例如:


  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>回调</title>
  8. </head>
  9. <body>
  10. <button>点击</button>
  11. <p></p>
  12. <script>
  13. var btn = document.querySelector('button');
  14. function fn1(){
  15. btn.onclick = function(){
  16. document.querySelector('p').innerHTML = '我出现了!'
  17. }
  18. }
  19. setTimeout(fn1,1000)
  20. </script>
  21. </body>
  22. </html>

 

 它的第一个参数是个回调函数,第二个参数是毫秒数,这个函数执行之后会产生一个子线程,子线程会等待 1 秒,然后执行回调函数 "fn1",在命令行输出 "我出现了!"。

Promise 的使用

语法格式:


  1. new Promise(function (resolve, reject) {
  2. console.log("Run");
  3. });

resolve和reject是参数 

再看这个例子:


  1. new Promise(function (resolve, reject) {
  2. var a = 0;
  3. var b = 1;
  4. if (b == 0) reject("Divide zero");
  5. else resolve(a / b);
  6. }).then(function (value) {
  7. console.log("a / b = " + value);
  8. }).catch(function (err) {
  9. console.log(err);
  10. }).finally(function () {
  11. console.log("End");
  12. });

这段打印结果为:

.then() .catch() 和 .finally() 三个方法

这三个方法的参数都是一个函数,

.then() 可以将参数中的函数添加到当前 Promise 的正常执行序列,

.catch() 则是设定 Promise 的异常处理序列,

.finally() 是在 Promise 执行的最后一定会执行的序列。 .then() 传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch 序列:


  1. new Promise(function (resolve, reject) {
  2. console.log(1111);
  3. resolve(2222);
  4. }).then(function (value) {
  5. console.log(value);
  6. return 3333;
  7. }).then(function (value) {
  8. console.log(value);
  9. throw "An error";
  10. }).catch(function (err) {
  11. console.log(err);
  12. });

打印结果为:

1111
2222
3333
An error

resolve() 中可以放置一个参数用于向下一个 then 传递一个值,then 中的函数也可以返回一个值传递给 then。但是,如果 then 中返回的是一个 Promise 对象,那么下一个 then 将相当于对这个返回的 Promise 进行操作,这一点从刚才的计时器的例子中可以看出来。

reject() 参数中一般会传递一个异常给之后的 catch 函数用于处理异常。

但是请注意以下两点:

  • resolve 和 reject 的作用域只有起始函数,不包括 then 以及其他序列;
  • resolve 和 reject 并不能够使起始函数停止运行,别忘了 return。




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

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

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

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

【举栗说明】JavaScript作用域,一次性给你总结!

前端达人

图片

本文重点

  • 函数案例

  • 函数作为参数使用

  • arguments

  • 作用域:写代码要注意变量的在哪声明和使用的问题

  • 预解析:什么叫预解析, 什么东西发生了什么事

01 作用域:使用范围

全局变量:

  • 声明的变量是使用var声明的,那么这个变量就是全局变量,

  • 全局变量可以在页面的任何位置使用

  • 除了函数以外,其他的任何位置定义的变量都是全局变量

  • 如果页面不关闭,那么就不会释放,就会占空间,消耗内存

  • 全局作用域:全局变量的使用范围

局部变量:

  • 在函数内部定义的变量,是局部变量,外面不能使用

  • 局部作用域:局部变量的使用范围

注意:

块级作用域:一对大括号就可以看成是一块,在这块区域中定义的变量,只能在这个区域中使用,但是在js中在这个块级作用域中定义的变量,外面也能使用;

说明:js没有块级作用域,只有函数除外

隐式全局变量:声明的变量没有var,就叫隐式全局变量

全局变量是不能被删除的,隐式全局变量是可以被删除的

定义变量使用var是不会被删除的,没有var是可以删除的

function f1() {  number=1000;//是隐式全局变量 }f1();console.log(number);   var num1=10;  num2=20;  delete num1;//把num1删除了  delete num2;//把num2删除了  console.log(typeof num1);  console.log(num1+10);  console.log(typeof num2);  num=100; console.log(num);  function f1() {  var num=100;  num+=10; }f1();//这个函数结束之后 { var num=10;  console.log(num);//10 }console.log(num);  if(true){  var num=10; }console.log(num); for(var i=0;i<5;i++){  var number=20; }console.log(number);   var i=0;  while (i<5){  var num=100;  i++;  } console.log(num);  function f1() {  var num=10; }f1(); console.log(num);  var num=10; console.log(num);//10  

作用域链

 var num=10;  function f1() {  var num=20;  function f2() {  var num=30;  function f3() {  var num=50;  console.log(num);  } f3();  } f2();  } f1(); 

03 函数案例

求2个数中的最大值

 function getMax(num1, num2) {  return num1 > num2 ? num1 : num2;  } console.log(getMax(10,20));  //console.log(getMax);//函数的代码 function getMax(num1, num2) {  return num1 > num2 ? num1 : num2;  } var num1=10;  var num2=20;  //函数外面的num1和函数的形参num1不是同一个变量 var result=getMax(num1,num2);  console.log(result);  console.log(getMax);//函数的代码 

求3个数中的最大值

 function getThreeMax(x, y, z) {  return x > y ? (x > z ? x : z) : (y > z ? y : z);  } console.log(getThreeMax(10,2,24)); 

判断一个数是否是素数(质数),只能被1和自身整除,质数是从2开始

用这个数字和这个数字前面的所有的数字整除一次(没有1的,没有自身的)

 function isPrimeNumber(num) {  for (var i = 2; i < num; i++) {  if (num % i == 0) {  //说明有一个数字整除了,就没有必要向后继续整除了, //此时就已经验证出不是质数 return false;  } } return true;  }//  console.log(isPrimeNumber(7) ? "yyyyyes" : "nnnnnno") var aa = isPrimeNumber(17);  if (aa) {  console.log("yes");  } else {  console.log("no");  }  function isPrimeNumber(num) {  for(var i=2;i<num;i++){  if(num%i==0){  //说明有一个数字整除了,就没有必要向后继续整除了,此时就已经验证出不是质数 return false;  } } return true;  } console.log(isPrimeNumber(8)?"是质数":"不是质数");   var result=isPrimeNumber(2);  if(result){  console.log("这个数字是质数");  }else{  console.log("这个数字不是质数");  }  function aaa(x,y){  return x-y;  } console.log(aaa(99,88)) 

通过函数实现数组反转

 function reverseArray(arr) {  for (var i = 0; i < arr.length / 2; i++) {  var temp = arr[i];  arr[i] = arr[arr.length - 1 - i];  arr[arr.length - 1 - i] = temp;  } return arr;  } console.log(reverseArray([1, 2, 3, 4, 5])); 

通过函数实现冒泡排序

 function sortArray(arr) {  //控制比较的轮数 for (var i = 0; i < arr.length - 1; i++) {  //控制每一轮的比较次数 for (var j = 0; j < arr.length - 1 - i; j++) {  if (arr[j] > arr[j + 1]) {  var temp = arr[j];  arr[j] = arr[j + 1];  arr[j + 1] = temp;  }//end if }//end for }//end for return arr; } console.log(sortArray([0, 19, 34, 10, 100, 2])); 

求一个数字的阶乘

function getJieCheng(num) {  var result = 1;  for (var i = 1; i <= num; i++) {  result *= i;  } return result; }console.log(getJieCheng(5));//1*2*3*4*5 

求斐波那契数列

 function getFib(num){  var num1=1;  var num2=1;  var num3=0;  for(var i=3;i<=nnum;i++){  sum=num1+num2;  num1=num2;  num2=sum;  } return sum;  } console.log(getFib(12))  

02 函数作为参数使用

函数是有数据类型,数据类型:是function类型的

函数可以作为参数使用,如果一个函数作为参数,那么我们说这个参数(函数)可以叫回调函数 只要是看到一个函数作为参数使用了,那就是回调函数

function sayHi(fn) {   console.log("GOOD");  fn();//fn此时应该是一个函数}function suSay() {  console.log("HELLO"); }sayHi(suSay); function f1(x,y) {  console.log(x+y); }f1(10,20); function f2(x,y) {  console.log(x+y); }f2("HLS","MISS"); function f3(x) {  console.log(x); }f3(true);

04 arguments

计算n个数字的和

定义一个函数,如果不确定用户是否传入了参数,或者说不知道用户传了几个参数,没办法计算,但是如果在函数中知道了参数的个数,等于也知道了每个参数的值.

//定义function f1() {  //获取的是函数在调用的时候,传入了几个参数 //console.log(arguments.length);  //使用arguments对象可以获取传入的每个参数的值 console.log(arguments); } f1(10,20,30,40,100,200);//调用 
 function f1({  //arguments----->数组使用------伪数组--- var sum=0;  for(var i=0;i<arguments.length;i++){  sum+=arguments[i];  } return sum;  } console.log(f1(10,20,30)); 

05 预解析:提前解析代码

预解析:就是在解析代码之前,预解析做什么事?

把变量的声明提前了----提前到当前所在的作用域的最上面

函数的声明也会被提前—提前到当前所在的作用域的最上面

函数调用的时候, 把会函数的声明提升到作用域的上面

函数的声明提升到作用域

 f1();//调用  var num=20;//这个变量的声明会提升到变量使用之前  function f1() {  console.log(num);  //var num=10;  } function f1() {  console.log("小苏好猥琐");  } f1();  function f1() {  console.log("小苏没有助教猥琐");  } f1(); 

把变量的声明提前

 var num;  console.log(num);  num=10;  function f1() {  console.log("哈哈,助教好猥琐哦");  }   //f1();//报错 

注意:预解析中,变量的提升,只会在当前的作用域中提升,提前到当前的作用域的最上面

  function f1({  console.log(num);//undefined  var num = 10;  } f1();   console.log(num);//报错  

函数中的变量只会提前到函数的作用域中的最前面,不会出去

预解析会分段(多对的script标签中函数重名,预解析的时候不会冲突)

 function f1({  console.log(num);//undefined  var num=10; } f1(); console.log(num);// function f1() { console.log("哈哈"); }

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

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

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

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

注册登录功能的完善

前端达人

在前面项目的基础上继续,因为我们的项目进来页面主题就是用户数据,所以我们想让它一进来就是高亮状态,那么我们可以这样做,同时我们再加上一个菜单:

<template> <div> <el-menu
                        style="width: 200px; min-height: calc(100vh - 50px)" default-active="user" :default-openeds="[1]" class="el-menu-vertical-demo"> <!--这是两个函数,我们可以先不写@open="handleOpen"--> <!--@close="handleClose"--> <el-sub-menu index="1"> <template #title>系统管理</template> <el-menu-item index="user" :route-="{path:'/'}">用户管理</el-menu-item> </el-sub-menu> <el-menu-item index="data" :route-="{path:'/'}">数据管理</el-menu-item> </el-menu> </div> </template> <script> export default { name: "Aside" } </script> <style scoped> </style>  
  • 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

访问效果如下:
在这里插入图片描述
可以看到一进来因为页面主体是用户管理界面,所以“用户管理”菜单栏是默认高亮的,然后还多了一个数据管理的菜单栏。
菜单之间怎么跳转一会儿再讲,我们现在先写注册和登录。
在写注册和登录之前,我们先讲一下路由,可以看到我们这个路由文件下的文件中,默认的“/”访问的是Home文件:
在这里插入图片描述
Home页面写的就是我们这个用户表的增删改查,然后Home页面呢是在我们的App.vue中给它嵌入进去了的,<router-view>就是展示的Home,还有Header啊Aside等
在这里插入图片描述
首先我们尝试一下可不可以直接在路由文件下写上一个Login路由,同时我们在views页面下创建一个Login.vue,看看能不能成功:
在这里插入图片描述
注意引入路由的写法要特别注意,不能直接像下面这样写:
在这里插入图片描述

而应该用引入的方式;
在这里插入图片描述
现在我们重启访问/login:
在这里插入图片描述
成功;
但是同时我们也看到了问题,我们明明是登录界面,为什么进到了后台主页了,而我们想要的登录界面应该是一个非常独立的界面,所以我们的这个路由是有问题的。因为我们之前是直接使用App.vue作为项目的框架,其实这个App.vue在我们的main.js里面是引入进来了的:
在这里插入图片描述
引进来之后呢直接作为createApp的根节点来使用,所以这个App.vue这个界面呢,不适合用来作为我们的这个后台骨架来使用:
在这里插入图片描述
它应该是一个全局的根节点,所以我们需要把App.vue里面的东西把它给挪走,挪到另一个界面,我们要把App.vue呢给它空出来,让App.vue可以直接访问我们所有的界面。
怎么做呢?
我们在src目录下新建一个layout文件夹,这个文件夹呢就用来做我们项目的骨架部分,再在这个文件下建一个Layout组件:
在这里插入图片描述
然后把之前在App.vue的东西copy过来:
在这里插入图片描述
然后Header啊Aside啊那些组件我们需要在这个组件里面进行引入,然后App里面的那些原来引入的就删掉就行了:
在这里插入图片描述
然后现在我们就完成了迁移,现在我们要去配置一下我们的路由,实现我们后台的一个访问。
路由怎么配置呢?非常简单。
我们来讲解一下刚才这个什么意思,App.vue里面我们只写了一个router-view,而这个router-view呢就作为我们这个全局的一个根节点访问,
在这里插入图片描述这个router-view里面既可以是登录界面也可以是注册界面也可以是后台主体,就是根据它是路由进行一个展示。当我们访问到我们的后台主体的时候,会进行一个二次的嵌套路由,那这个嵌套路由怎么写呢?我们先配置登录页面的路由和后台管理布局的路由:
在这里插入图片描述

此时访问/和访问/login都能到达对应的页面:
在这里插入图片描述

在这里插入图片描述
但是访问/时,Home主体页面并没有出来,只出来了/对应的页面骨架的路由,怎么让这个Home主体页面出来呢,这就涉及到了嵌套路由,像下面这样写,children属性是一个数组属性,意味着其可以嵌套多个路由:
在这里插入图片描述
访问/下的home路由,可以看到如下页面:
在这里插入图片描述

vue-router给我们提供了重定向属性,可以让我们在访问某个路由页面时自动重定向到一个我们指定的路由页面:
在这里插入图片描述
现在我们直接访问/试试,可以看到依然是访问的home页面:
在这里插入图片描述
现在路由问题解决之后我们就可以去写我们的登录页面了。

<template> <!--将整个浏览器页面放在一个大div里
    width: 100%表示这个让div撑满全屏
    height: 100vh同上,一个撑满高度一个撑满宽度--> <div style="width: 100%; height: 100vh;background: darkslateblue; overflow: hidden"> <!--margin: 参数1 参数2; 参数1表示上下距离,参数2表示左右距离,auto表示自动匹配
        如果页面产生了空白,就在外层最大的div上加一个overflow,设置为hidden即可--> <div style="width: 400px; margin: 150px auto"> <!--font-size表示字体大小,text-align表示字体居中--> <div style="color: #cccccc; font-size: 30px; text-align: center; padding: 30px 0"> 欢迎登录 </div> <!--然后去element上copy一个表单--> <el-form ref="form" :model="form" size="normal"> <el-form-item> <el-input prefix-icon="el-icon-user-solid" v-model="form.username"></el-input> </el-form-item> </el-form> <el-form ref="form" :model="form" size="normal"> <el-form-item> <el-input prefix-icon="el-icon-lock" v-model="form.password" show-password></el-input> </el-form-item> </el-form> <el-form ref="form" :model="form" size="normal"> <el-button style="width: 100%" type="primary" @click="login">登录</el-button> </el-form> </div> </div> </template> <script> import request from "../utils/request"; export default { name: "Login", data(){ return{ form:{} } }, methods: { login() { request.post("/api/user/login",this.form).then(res => { if(res.code === "0"){ this.$messageBox({ type: "success", message: "登录成功" }) //    登录成功之后进行页面跳转,跳转到主页 this.$router.push("/") }else{ this.$messageBox({ type: "error", message: res.msg }) } }) } } } </script> <style scoped> </style>  
  • 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

然后现在去写我们后端的接口:

 //用户登录 @PostMapping("/login") public Result login(@RequestBody User user){ User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername()).eq(User::getPassword,user.getPassword())); if(res != null){ //登录成功 return Result.success(); }else{ //登录失败 return Result.error("-1","用户名或密码错误"); } }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

现在数据库中的数据有:
在这里插入图片描述
我们试着访问登录:
在这里插入图片描述
可以看到登录成功:
在这里插入图片描述
然后我们再去我们的网页头部右侧的用户信息栏写一下退出系统的操作:
在这里插入图片描述
点击则路由跳转到登录页面。
然后还有注册页面,也一起写了,注册页面其实逻辑和登录界面差不多,我们copy一个登录组件进行更改即可。
在这里插入图片描述
然后进行更改就行了,注册不过就比登录多了一个确认密码的操作。

<template> <!--将整个浏览器页面放在一个大div里
    width: 100%表示这个让div撑满全屏
    height: 100vh同上,一个撑满高度一个撑满宽度--> <div style="width: 100%; height: 100vh;background: darkslateblue; overflow: hidden"> <!--margin: 参数1 参数2; 参数1表示上下距离,参数2表示左右距离,auto表示自动匹配
        如果页面产生了空白,就在外层最大的div上加一个overflow,设置为hidden即可--> <div style="width: 400px; margin: 150px auto"> <!--font-size表示字体大小,text-align表示字体居中--> <div style="color: #cccccc; font-size: 30px; text-align: center; padding: 30px 0"> 欢迎登录 </div> <!--然后去element上copy一个表单--> <el-form ref="form" :model="form" size="normal" :rules="rules"> <el-form-item prop="username"> <el-input prefix-icon="el-icon-user-solid" v-model="form.username"></el-input> </el-form-item> <el-form-item prop="password"> <el-input prefix-icon="el-icon-lock" v-model="form.password" show-password></el-input> </el-form-item> </el-form> <el-form ref="form" :model="form" size="normal"> <el-button style="width: 100%" type="primary" @click="login">登录</el-button> </el-form> </div> </div> </template> <script> import request from "../utils/request"; export default { name: "Login", data(){ return{ form:{}, rules:{ username:[ {required: true,message:"请输入用户名",trigger:'blur'}, ], password:[ {required: true,message:"请输入密码",trigger:'blur'}, ] } } }, methods: { login() { //发送请求之前先加这个判断,不为空且满足规则时才发送请求 this.$refs['form'].validate((valid) => { if (valid) { request.post("/api/user/login",this.form).then(res => { if(res.code === "0"){ this.$messageBox({ type: "success", message: "登录成功" }) //    登录成功之后进行页面跳转,跳转到主页 this.$router.push("/") }else{ this.$messageBox({ type: "error", message: res.msg }) } }) } }) } } } </script> <style scoped> </style>  
  • 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

其中我们还要注意在请求数据之前要先判断表单内部是否数据符合要求,否则不予请求,同样在Login页面内也要加入该判断:

<template> <!--将整个浏览器页面放在一个大div里
    width: 100%表示这个让div撑满全屏
    height: 100vh同上,一个撑满高度一个撑满宽度--> <div style="width: 100%; height: 100vh;background: darkslateblue; overflow: hidden"> <!--margin: 参数1 参数2; 参数1表示上下距离,参数2表示左右距离,auto表示自动匹配
        如果页面产生了空白,就在外层最大的div上加一个overflow,设置为hidden即可--> <div style="width: 400px; margin: 150px auto"> <!--font-size表示字体大小,text-align表示字体居中--> <div style="color: #cccccc; font-size: 30px; text-align: center; padding: 30px 0"> 欢迎登录 </div> <!--然后去element上copy一个表单--> <el-form ref="form" :model="form" size="normal" :rules="rules"> <el-form-item prop="username"> <el-input prefix-icon="el-icon-user-solid" v-model="form.username"></el-input> </el-form-item> <el-form-item prop="password"> <el-input prefix-icon="el-icon-lock" v-model="form.password" show-password></el-input> </el-form-item> </el-form> <el-form ref="form" :model="form" size="normal"> <el-button style="width: 100%" type="primary" @click="login">登录</el-button> </el-form> </div> </div> </template> <script> import request from "../utils/request"; export default { name: "Login", data(){ return{ form:{}, rules:{ username:[ {required: true,message:"请输入用户名",trigger:'blur'}, ], password:[ {required: true,message:"请输入密码",trigger:'blur'}, ] } } }, methods: { login() { //发送请求之前先加这个判断,不为空且满足规则时才发送请求 this.$refs['form'].validate((valid) => { if (valid) { request.post("/api/user/login",this.form).then(res => { if(res.code === "0"){ this.$messageBox({ type: "success", message: "登录成功" }) //    登录成功之后进行页面跳转,跳转到主页 this.$router.push("/") }else{ this.$messageBox({ type: "error", message: res.msg }) } }) } }) } } } </script> <style scoped> </style>  
  • 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

然后现在去后端写register的接口:

//用户注册 @PostMapping("/register") public Result register(@RequestBody User user){ User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername())); if(res != null){ //说明用户名重复 return Result.success(); } //该用户不存在,予以注册 if(user.getPassword() == null){ user.setPassword("123456"); } userMapper.insert(user); return Result.success(); }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

就此我们的注册页面也写完啦。

1





























































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

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

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

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

掌握用Vue脚手架搭建一个完整项目!

前端达人

1.在搭建项目之前,先安装淘宝镜像和命令行工具,可能需要等待一段时间(电脑安装过一遍之后,以后建项目时就不需要再安装):

        a.Win+R打开命令提示行cmd;

        b.进入命令行cmd,设置淘宝镜像;

npm config set registry https://registry.npm.taobao.org

        c.安装可生成脚手架代码的命令行工具;

npm i -g @vue/cli

        当命令行窗口显示 [ + @vue/cli@版本号 ] 时说明安装成功。

2.开始创建项目

        a.先决定要把项目文件夹保存在哪个位置;此处以test文件夹为例;

        b.进入test文件夹后,shift+鼠标右键打开power shell窗口;

c.运行 vue create 自定义项目名;此处以项目名为test为例,出现提示后按以下过程进行选择:

        1)? Please pick a preset:

        2)? Check the features needed for your project:

        3)? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n)  N

        4)? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): (Use arrow keys)

        5)? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)

        6)? Save this as a preset for future projects? (y/N)  N

        最后命令行窗口显示Successfully created project xzvue说明项目创建成功。

        此时我们便可在test文件夹中看到整个项目。

3.使用vscode打开并运行脚手架项目

(1)右键单击package.json文件,选择"在集成终端中打开";

(2)在终端窗口中输入:npm run serve,等待后出现App running at : - Local :http://localhost:8080/,如下:

(3)按住Ctrl,点local:右侧的连接,即可自动打开浏览器。 

        需要的时候就可以在集成终端中输入npm inpm i vant -S 等命令下载node_modules包、安装vant等等。

        注意vue采用的是热编译,修改后无需停止或重启项目,只要一修改,就会立刻自动重新编译,重新运行,自动在界面上显示新内容。



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

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

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

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

配合前端vue实现表格的增删改查

前端达人

前言:

        这个章节内容是比较多的,分为前端部分和后端部分。

目录:

实现效果:增删改查

 一、后端部分:

(1)数据库:

        新建一张表user,设置几个字段,效果如下:

 (2)egg逻辑部分:

提供的接口:http://localhost:7001/setUserList

 (3)egg具体实现步骤:

1、router.js中添加:

2、新建:app / controller / new / user.js

(1)查,模糊查询 

(2)增

 (3)改

 (4)删

 user.js 源码:

3、引入mysql:点我

4、跨域问题解决:点我

 二、前端部分:

新建vue文件:testApi.vue

1、初始化查询列表数据:页面展示列表,列表数据mouted获取

2、页面点击新增:展示弹框,并将弹框内容去除掉,点击新增,将弹框内容发送给后端

 3、页面点击列表里面具体数据的编辑:弹框,并回填数据,修改将当前数据的id和表格数据传给后端

4、删除按钮,点击出现二次确认弹框,点击确认将当前数据的id给后端就行 

 testApi.vue 源码:


实现效果:增删改查

 一、后端部分:

(1)数据库:

        新建一张表user,设置几个字段,效果如下:

 (2)egg逻辑部分:

提供的接口:http://localhost:7001/setUserList

  1. get 请求,获取数据,支持模糊查询
  2. post 请求,新增数据
  3. put 请求,给后端当前数据id,修改内容
  4. delete 请求,根据数据id删除当前条数据

 (3)egg具体实现步骤:

1、router.js中添加:

 
  1. /**
  2. * 路由配置
  3. * @param app
  4. */
  5. module.exports = app => {
  6. const { router, controller } = app;
  7. //--------------------------------------------------
  8. // server接口
  9. //--------------------------------------------------
  10. app.get('/setUserList', controller.new.user.getUserList);
  11. app.post('/setUserList', controller.new.user.postUserList);
  12. app.put('/setUserList', controller.new.user.putUserList);
  13. app.delete('/setUserList', controller.new.user.deleteUserList);
  14. }

2、新建:app / controller / new / user.js

(1)查,模糊查询 

select * from user where name like ? % 内容 %

(2)增

this.app.mysql.insert('表名',内容)

 (3)改

UPDATE loginlist SET `password` = 'Ad123456' WHERE id = 2

 (4)删

delete from user where id = 1

 user.js 源码:

 
  1. /**
  2. * 用户信息路由
  3. * @param app
  4. * @returns {HomeController}
  5. */
  6. const Controller = require('egg').Controller;
  7. class NewsController extends Controller {
  8. async getUserList() {
  9. //查询库里的user表
  10. let params = this.ctx.query //获取路径后面的参数
  11. console.log('用户的参数:');
  12. console.log(params);
  13. let sql = 'select * from user'
  14. let initSql = sql
  15. let content = [];//参数
  16. let isMore = false;//是否有多个查询参数
  17. /**
  18. * @模糊查询-量大的时候效率低
  19. * select * from user where name like ? % 内容 %
  20. * 在user表中全局查找name值 == 内容的
  21. * % 内容 % 全局查找内容
  22. * 内容 % 查找以 内容 开头的数据
  23. * */
  24. if(params.name){
  25. sql += " where name like ?";
  26. content.push( "%"+params.name+"%" );
  27. isMore = true;
  28. }
  29. if(params.age){
  30. if(isMore){//true代表有多个参数
  31. sql += "and age LIKE ?";//and是两个条件都必须满足,or是或的关系
  32. }else{
  33. sql += " WHERE age LIKE ?";
  34. }
  35. content.push( "%"+params.age+"%" )
  36. isMore = true;
  37. }
  38. if(params.address){
  39. if(isMore){//true代表有多个参数
  40. sql += "and address LIKE ?";//and是两个条件都必须满足,or是或的关系
  41. }else{
  42. sql += " WHERE address LIKE ?";
  43. }
  44. content.push( "%"+params.address+"%" )
  45. isMore = true;
  46. }
  47. if(params.phone){
  48. if(isMore){//true代表有多个参数
  49. sql += "and phone LIKE ?";//and是两个条件都必须满足,or是或的关系
  50. }else{
  51. sql += " WHERE phone LIKE ?";
  52. }
  53. content.push( "%"+params.phone+"%" )
  54. }
  55. //开启分页
  56. if(params.page || params.pageSize){
  57. let current = params.page;//当前页码
  58. let pageSize = params.pageSize;//一页展示多少条数据
  59. sql += " limit ?,?";
  60. content.push((current-1)*pageSize,parseInt(pageSize));
  61. }
  62. let allList = await this.app.mysql.query(initSql);
  63. let userList= await this.app.mysql.query(
  64. sql,content
  65. );
  66. this.ctx.body = {
  67. code:200,
  68. masg:'success',
  69. data: {
  70. list:userList,
  71. total:allList.length
  72. }
  73. };
  74. }
  75. /**
  76. * 新增用户信息
  77. * INSERT INTO loginlist (aaa,bbb,ccc) VALUES ('"'+111+'","'+222+'","'+333+'"')
  78. * this.app.mysql.insert('表名',内容)
  79. * this.app.mysql.insert('表名',{
  80. * name:123,
  81. * age:1,
  82. * address:西安
  83. * })
  84. */
  85. //
  86. async postUserList() {
  87. console.log(this.ctx.request.body);
  88. //新增数据-user表
  89. let data = this.ctx.request.body
  90. data.id = parseInt(Math.random()*100000)
  91. let insertResult = await this.app.mysql.insert(
  92. 'user', data
  93. );
  94. this.ctx.body = {
  95. code:200,
  96. masg:'success',
  97. data:insertResult
  98. };
  99. }
  100. /**
  101. * 修改用户信息
  102. * UPDATE loginlist SET `password` = 'Ad123456' WHERE id = 2(唯一值),修改一个
  103. * UPDATE loginlist SET username = 'admins', `password` = 'Ad123456' WHERE id = 2,修改多个
  104. */
  105. async putUserList(){
  106. //新增数据-user表
  107. let id = this.ctx.query.id //获取路径后面的参数
  108. let data = this.ctx.request.body
  109. let sql = 'update user set '
  110. let isMore = false;//是否有多个查询参数
  111. if(!id){
  112. this.ctx.body = {
  113. code:200,
  114. masg:'warning',
  115. data:'id没有传'
  116. };
  117. return
  118. }
  119. //姓名
  120. if(data.name){
  121. sql += 'name = "'+data.name+'"'
  122. isMore = true
  123. }
  124. //年龄
  125. if(data.age){
  126. if(isMore){
  127. sql += ',age = "'+data.age+'"'
  128. }else{
  129. sql += 'age = "'+data.age+'"'
  130. }
  131. isMore = true
  132. }
  133. //地址
  134. if(data.address){
  135. if(isMore){
  136. sql += ',address = "'+data.address+'"'
  137. }else{
  138. sql += 'address = "'+data.address+'"'
  139. }
  140. isMore = true
  141. }
  142. //手机号
  143. if(data.phone){
  144. if(isMore){
  145. sql += ',phone = "'+data.phone+'"'
  146. }else{
  147. sql += 'phone = "'+data.phone+'"'
  148. }
  149. isMore = true
  150. }
  151. //邮箱地址
  152. if(data.email){
  153. if(isMore){
  154. sql += ',email = "'+data.email+'"'
  155. }else{
  156. sql += 'email = "'+data.email+'"'
  157. }
  158. }
  159. sql += ' where id = ' + id
  160. let insertResult = await this.app.mysql.query(sql)
  161. this.ctx.body = {
  162. code:200,
  163. masg:'success',
  164. data:insertResult
  165. };
  166. }
  167. /**
  168. * 注销用户接口
  169. * DELETE FROM loginlist WHERE username = 'superman'
  170. */
  171. async deleteUserList(){
  172. //查询库里的user表
  173. let params = this.ctx.query //获取路径后面的参数
  174. console.log('用户的参数:');
  175. console.log(params);
  176. let sql = 'delete from user where id = '+ params.id
  177. let res = await this.app.mysql.query(
  178. sql
  179. );
  180. this.ctx.body = {
  181. code:200,
  182. masg:'success',
  183. data:res
  184. };
  185. }
  186. /**
  187. * 模糊查询封装方法
  188. * @params = auth
  189. * */
  190. async query( auth ) {
  191. const TABLE_NAME = 'user';
  192. const QUERY_STR = 'id, name, age, phone, address';
  193. let sql = `select ${QUERY_STR} from ${TABLE_NAME} where authName like "%${auth.authName}%"`;
  194. const row = await this.app.mysql.query(sql);
  195. return row;
  196. }
  197. }
  198. module.exports = NewsController;

3、引入mysql:点我

4、跨域问题解决:点我

 二、前端部分:

新建vue文件:testApi.vue

1、初始化查询列表数据:页面展示列表,列表数据mouted获取

 
  1. <el-table
  2. :data="tableInfo.list"
  3. style="width: 100%">
  4. <el-table-column
  5. type="index"
  6. label="序号"
  7. align="center">
  8. </el-table-column>
  9. <el-table-column
  10. prop="name"
  11. label="姓名"
  12. align="center">
  13. </el-table-column>
  14. <el-table-column
  15. prop="age"
  16. label="年龄"
  17. align="center">
  18. </el-table-column>
  19. <el-table-column
  20. prop="address"
  21. label="地址">
  22. </el-table-column>
  23. <el-table-column
  24. prop="phone"
  25. label="手机号">
  26. </el-table-column>
  27. <el-table-column
  28. prop="email"
  29. label="邮箱">
  30. </el-table-column>
  31. <el-table-column
  32. label="操作"
  33. width="100">
  34. <template slot-scope="scope">
  35. <el-button type="text" size="small" @click="editFun(scope.row)">编辑</el-button>
  36. <el-button type="text" size="small" @click="deleteFun(scope.row)">删除</el-button>
  37. </template>
  38. </el-table-column>
  39. </el-table>
 
  1. mounted(){
  2. this.initPage()
  3. },
  4. methods: {
  5. /***
  6. * 获取列表数据
  7. */
  8. initPage() {
  9. let params = {
  10. page: this.tableInfo.page, //当前页
  11. pageSize: this.tableInfo.pageSize //一页展示多少条
  12. }
  13. this.$axios.get('http://localhost:7001/setUserList',{
  14. params
  15. }).then(res => {
  16. this.tableInfo.list = res.data.data.list
  17. this.tableInfo.total = res.data.data.total
  18. }).catch(error => {
  19. this.$message(error.data.message)
  20. })
  21. },
  22. }

2、页面点击新增:展示弹框,并将弹框内容去除掉,点击新增,将弹框内容发送给后端

 3、页面点击列表里面具体数据的编辑:弹框,并回填数据,修改将当前数据的id和表格数据传给后端

 

 

4、删除按钮,点击出现二次确认弹框,点击确认将当前数据的id给后端就行 

 testApi.vue 源码:

 
  1. <template>
  2. <div class="pro_body">
  3. <el-button type='success' @click="addModal">新增</el-button>
  4. <el-table
  5. :data="tableInfo.list"
  6. style="width: 100%">
  7. <el-table-column
  8. type="index"
  9. label="序号"
  10. align="center">
  11. </el-table-column>
  12. <el-table-column
  13. prop="name"
  14. label="姓名"
  15. align="center">
  16. </el-table-column>
  17. <el-table-column
  18. prop="age"
  19. label="年龄"
  20. align="center">
  21. </el-table-column>
  22. <el-table-column
  23. prop="address"
  24. label="地址">
  25. </el-table-column>
  26. <el-table-column
  27. prop="phone"
  28. label="手机号">
  29. </el-table-column>
  30. <el-table-column
  31. prop="email"
  32. label="邮箱">
  33. </el-table-column>
  34. <el-table-column
  35. label="操作"
  36. width="100">
  37. <template slot-scope="scope">
  38. <el-button type="text" size="small" @click="editFun(scope.row)">编辑</el-button>
  39. <el-button type="text" size="small" @click="deleteFun(scope.row)">删除</el-button>
  40. </template>
  41. </el-table-column>
  42. </el-table>
  43. <el-pagination
  44. class="work_pagination"
  45. background
  46. :layout="'total,prev, pager, next,sizes'"
  47. :total="tableInfo.total"
  48. :hide-on-single-page="false"
  49. :current-page="tableInfo.page"
  50. :page-size="tableInfo.pageSize"
  51. @current-change="pageChange"
  52. @size-change="pageSizeChange"
  53. >
  54. </el-pagination>
  55. <!--弹框部分-->
  56. <el-dialog
  57. custom-class="modalName"
  58. :visible.sync="modal.show"
  59. :width="modal.type === 'delete'? '470px' : '800px'">
  60. <h3 v-if="modal.type === 'add'" slot="title">新增</h3>
  61. <h3 v-if="modal.type === 'edit'" slot="title">修改</h3>
  62. <h3 v-if="modal.type === 'delete'" slot="title">提示</h3>
  63. <div v-if="modal.type !== 'delete'" class="editNameBody">
  64. <el-form class="editNameFrom" :model="modalFrom" label-width="120px" label-position="right">
  65. <el-form-item label="姓名:">
  66. <el-input v-model="modalFrom.name"></el-input>
  67. </el-form-item>
  68. <el-form-item label="年纪:">
  69. <el-input v-model="modalFrom.age"></el-input>
  70. </el-form-item>
  71. <el-form-item label="手机号:">
  72. <el-input v-model="modalFrom.phone"></el-input>
  73. </el-form-item>
  74. <el-form-item label="邮箱:">
  75. <el-input v-model="modalFrom.email"></el-input>
  76. </el-form-item>
  77. <el-form-item label="地址:">
  78. <el-input v-model="modalFrom.address" type="textarea"></el-input>
  79. </el-form-item>
  80. </el-form>
  81. </div>
  82. <div v-if="modal.type === 'delete'">
  83. <i class="el-icon-warning" style="margin-right:7px;color:#FFAA00;font-size: 16px;"></i>请确认是否删除
  84. </div>
  85. <div slot="footer" class="dialog-footer">
  86. <el-button @click="modal.show = false">取 消</el-button>
  87. <el-button v-if="modal.type === 'add'" type="primary" @click="addUserList">新增</el-button>
  88. <el-button v-if="modal.type === 'edit'" type="primary" @click="editUserList">修改</el-button>
  89. <el-button v-if="modal.type === 'delete'" type="primary" @click="deleteUserList">确 认</el-button>
  90. </div>
  91. </el-dialog>
  92. </div>
  93. </template>
  94. <script>
  95. export default {
  96. data() {
  97. return {
  98. tableInfo:{
  99. columns:[
  100. {
  101. title: '序号',
  102. type: 'index',
  103. },{
  104. title: '姓名',
  105. prop: 'name',
  106. align: 'center'
  107. },
  108. {
  109. title: '年龄',
  110. prop: 'age',
  111. align: 'center'
  112. },{
  113. title: '地址',
  114. prop: 'address',
  115. align: 'center'
  116. },{
  117. title: '邮箱',
  118. prop: 'email',
  119. align: 'center'
  120. },{
  121. title: '手机号',
  122. prop: 'phone',
  123. align: 'center'
  124. },
  125. {//内容slot
  126. slot: 'operateT'
  127. }
  128. ],
  129. list:[],
  130. page:1,
  131. pageSize:10,
  132. total:0,
  133. },
  134. modal:{
  135. show:false,
  136. type:'add'
  137. },
  138. modalFrom:{
  139. name:'',
  140. age:'',
  141. phone:'',
  142. address:'',
  143. email:''
  144. }
  145. };
  146. },
  147. mounted(){
  148. this.initPage()
  149. },
  150. methods: {
  151. /***
  152. * 获取列表数据
  153. */
  154. initPage() {
  155. let params = {
  156. page: this.tableInfo.page, //当前页
  157. pageSize: this.tableInfo.pageSize //一页展示多少条
  158. }
  159. this.$axios.get('http://localhost:7001/setUserList',{
  160. params
  161. }).then(res => {
  162. this.tableInfo.list = res.data.data.list
  163. this.tableInfo.total = res.data.data.total
  164. }).catch(error => {
  165. this.$message(error.data.message)
  166. })
  167. },
  168. /**
  169. * 当前页发生改变
  170. * */
  171. pageChange(page) {
  172. this.tableInfo.page = page
  173. this.initPage() //刷新列表数据
  174. },
  175. /**
  176. * 当前第几页发生改变
  177. * */
  178. pageSizeChange(pageSize) {
  179. this.tableInfo.page = 1
  180. this.tableInfo.pageSize = pageSize
  181. this.initPage() //刷新列表数据
  182. },
  183. //新增弹框
  184. addModal(){
  185. this.modalFrom ={
  186. name:'',
  187. age:'',
  188. phone:'',
  189. address:'',
  190. email:''
  191. }
  192. this.modal.show = true
  193. this.modal.type = 'add'
  194. },
  195. //修改弹框
  196. editFun(row){
  197. this.modalFrom = row
  198. this.modal.show = true
  199. this.modal.type = 'edit'
  200. },
  201. //删除弹框
  202. deleteFun(row){
  203. this.modalFrom = row
  204. this.modal.show = true
  205. this.modal.type = 'delete'
  206. },
  207. addUserList(){
  208. this.$axios({
  209. method:'post',
  210. url:'http://localhost:7001/setUserList',
  211. data:this.modalFrom
  212. }).then(res => {
  213. this.$message.success('新增成功')
  214. this.initPage() //刷新数据
  215. this.modal.show = false
  216. })
  217. },
  218. editUserList(){
  219. this.$axios({
  220. method:'put',
  221. url:'http://localhost:7001/setUserList',
  222. params:{
  223. id:this.modalFrom.id
  224. },
  225. data:this.modalFrom
  226. }).then(res => {
  227. this.$message.success('修改成功')
  228. this.initPage() //刷新数据
  229. this.modal.show = false
  230. })
  231. },
  232. deleteUserList(){
  233. this.$axios({
  234. method:'delete',
  235. url:'http://localhost:7001/setUserList',
  236. params:{
  237. id:this.modalFrom.id
  238. }
  239. }).then(res => {
  240. this.$message.success('删除成功')
  241. this.initPage() //刷新数据
  242. this.modal.show = false
  243. })
  244. }
  245. }
  246. }
  247. </script>
  248. <style lang='scss'>
  249. .modalName{
  250. h3{
  251. padding:10px;
  252. }
  253. }
  254. </style>


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

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

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

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

CORS和JSONP的区别,如何解决跨域问题?

前端达人

在我们了解JSONP 和 CORS 之前我们先明确一下:

我们为什么要使用cors和jsonp呢?

实际上,cors和jsonp都是用于解决跨域问题,当两个页面的协议、域名、端口号中有一个不一致时就存在了跨域,一旦出现跨域,浏览器发送跨域请求后,请求回来的数据都会被浏览器所拦截,准备一张图给大家看看:

 

核心点:如何实现跨域数据请求?(⭐⭐⭐⭐⭐)

现下实现跨域数据请求,最主要的两种解决方案分别是 JSONP 和 CORS 

JSONP  出现的早,兼容性好(兼容低版本 IE )。是前端程序员为了解决跨域问题,被迫想出来的一种 临时解决方案,最主要的缺点 是只支持 GET 请求,不支持 POST 请求。
CORS  出现的较晚,它是 W3C 标准,属于跨域 Ajax 请求的根本解决方案。支持 GET 和 POST 请 求。缺点 是不兼容某些低版本的浏览器。

什么是JSONP(⭐⭐⭐)

JSONP (JSON with Padding) 是 JSON 的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。

JSONP的实现原理(⭐⭐⭐) 

  1. 概念:浏览器端通过 <script> 标签的 src 属性,请求服务器上的数据,同时,服务器返回一个函数的调用。这种请求数据的方式叫做 JSONP

  2. 特点: 

   JSONP 不属于真正的 Ajax 请求,因为它没有使用 XMLHttpRequest 这个对象

    JSONP 仅支持 GET 请求,不支持 POSTPUTDELETE 等请求

什么是CORS(⭐⭐⭐⭐⭐)

  1. CORS (跨域资源共享) 由一系列 HTTP 响应头组成,这些 HTTP 响应头决定浏览器 是否阻止前端 JS 代码跨域获取资源

  2. 浏览器的同源安全策略默认会阻止网页“跨域”获取资源。但如果接口服务器配置了 CORS 相关的 HTTP 响应头,就可以解除浏览器端的跨域访问限制

 

 

下面分别向大家演示通过CORS和JSONP实现跨域的案例:

一、通过CORS中间件解决跨域问题 :

index.html文件代码演示:


    
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. <script src="jquery.min.js"></script>
  9. </head>
  10. <body>
  11. <button class="get">get请求</button>
  12. <button class="post">post请求</button>
  13. <script>
  14. $('.get').on('click', function() {
  15. $.ajax({
  16. method: 'get',
  17. url: 'http://127.0.0.1/api/get?name=hua&age=18',
  18. success: function(res) {
  19. console.log(res);
  20. }
  21. })
  22. })
  23. $('.post').on('click', function() {
  24. $.ajax({
  25. method: 'post',
  26. url: 'http://127.0.0.1/api/post',
  27. data: {
  28. name: 'lajitong',
  29. age: '111'
  30. },
  31. success: function(res) {
  32. console.log(res);
  33. }
  34. })
  35. })
  36. </script>
  37. </body>
  38. </html>

此时会出现跨域问题,我们需要使用 cors 中间件解决跨域问题

  1. cors 是 Express 的一个第三方中间件。通过安装和配置 cors 中间件,可以很方便地解决跨域问题

  2. 使用步骤

    • 安装中间件: npm install cors

    • 导入中间件: const cors = require('cors')

    • 配置中间件: 在路由之前调用app.use(cors())

  3. express接口案例代码


    
  1. // 导入 express 模块
  2. const express = require('express')
  3. // 创建 express 的服务器实例
  4. const app = express()
  5. // 导入中间件
  6. const cors = require('cors')
  7. // 配置中间件
  8. app.use(cors())
  9. // 配置解析表单数据的中间件
  10. app.use(express.urlencoded({ extended: false }))
  11. // 导入路由模块(被单独分离后导入)
  12. const router = require('./apiRouter')
  13. // 把路由模块,注册到 app 上
  14. app.use('/api', router)
  15. // 调用 app.listen 方法,指定端口号并启动 web 服务器
  16. app.listen(80, () => {
  17. console.log('http://127.0.0.1')
  18. })

apiRouter路由文件代码:


    
  1. const express = require('express');
  2. const router = express.Router();
  3. router.get('/get', (req, res) => {
  4. const query = req.query;
  5. res.send({
  6. status: 0,
  7. msg: 'get请求成功',
  8. data: query
  9. })
  10. })
  11. router.post('/post', (req, res) => {
  12. // const body = req.body; //获取客户端请求的数据
  13. res.send({
  14. status: 0,
  15. msg: 'post请求成功',
  16. data: req.body
  17. })
  18. })
  19. module.exports = router;

在终端中运行express接口代码后打开index.html文件并点击get及post按钮得到请求结果:

 二、通过JSONP中间件解决跨域问题 :

创建 JSONP 接口的注意事项

  1. 如果项目中已经配置了 CORS 跨域资源共享,为了防止冲突,必须在配置 CORS 中间件之前声明 JSONP 的接口

    否则 JSONP 接口会被处理成开启了 CORS 的接口

  2. 实现步骤:

        (1)获取客户端发送过来的回调函数的名字

        (2)得到要通过 JSONP 形式发送给客户端的数据

        (3)根据前两步得到的数据,拼接出一个函数调用的字符串

        (4)把上一步拼接得到的字符串,响应给客户端的 <script> 标签进行解析执行

案例代码如下:


    
  1. //导入express模块
  2. const express = require('express');
  3. //创建express服务器实例
  4. const app = express();
  5. //挂载路由
  6. app.get('/jsonp', (req, res) => {
  7. // 通过解构req.query客户端通过查询字符串的形式发送到客户端的参数fn
  8. const { callback } = req.query
  9. //在服务器端定义一个obj对象
  10. const obj = {
  11. uname: 'zjj',
  12. age: '18'
  13. }
  14. //obj对象转为res.send可处理的字符串形式后从服务器端相应回调函数至客户端
  15. res.send(`${callback}(${JSON.stringify(obj)})`)
  16. })
  17. app.listen(80, () => {
  18. console.log('http://127.0.0.1');
  19. })

创建jsonp.html客户端来接收服务器端响应过来的回调函数,代码如下:

url中callback=fn为客户端发送请求携带的参数 既服务器端中的req.query.callback


    
  1. <script>
  2. function fn(res) {
  3. console.log(res);
  4. }
  5. </script>
  6. <script src="http://127.0.0.1/jsonp?callback=fn"></script>




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

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

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

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

日历

链接

个人资料

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

存档