老项目, 不会react, vue框架。其他人会使用模板。bootstrap + jquery
布局:
https://getbootstrap.com/docs/4.6/getting-started/introduction/
html<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous">
<title>Hello, world!</title>
</head>
<body>
<h1>Hello, world!</h1>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script>
</body>
</html>
link css
script, 完成动画
jquery 插件
body中所有内容在以下容器中
<div class="container"> </div>
实现boogstrap网页
html<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous">
<title>Hello, world!</title>
<style>
.container {
border: 1px solid red;
}
.row {
border: 1px solid yellowgreen;
margin: 5px;
}
.row div {
border: 1px solid blue;
margin: 3px;
}
</style>
</head>
<body>
<h1>Hello, world!</h1>
栅格系统,每行12格 <br>
<div class="container">
<div class="row">
<!-- head -->
<div class="col-sm">
One of three columns
</div>
<div class="col-sm">
One of three columns
</div>
<div class="col-sm">
One of three columns
</div>
</div>
<!-- 侧边栏 页面 页内导航 -->
<div class="row">
<div class="col-3">
1 of 3
</div>
<div class="col">
2 of 3
</div>
<div class="col-3">
3 of 3
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script>
</body>
</html>
https://getbootstrap.com/docs/4.6/layout/overview/#containers
从上到下,适应小分辨率到大分辨率
将组件放在列中https://getbootstrap.com/docs/4.6/components/alerts/
html<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous">
<title>Hello, world!</title>
<style>
.container {
border: 1px solid red;
}
.row {
border: 1px solid yellowgreen;
margin: 5px;
}
.row div {
border: 1px solid blue;
margin: 3px;
}
</style>
</head>
<body>
<h1>Hello, world!</h1>
栅格系统,每行12格 <br>
<div class="container">
<div class="row">
<!-- head -->
<div class="col-sm">
One of three columns
</div>
<div class="col-sm">
One of three columns
</div>
<div class="col-sm">
One of three columns
</div>
</div>
<!-- 侧边栏 页面 页内导航 -->
<div class="row">
<div class="col-3">
1 of 3
</div>
<div class="col">
2 of 3
</div>
<div class="col-3">
<button type="button" class="btn btn-primary" onclick="test()">提交</button>
<button type="button" class="btn btn-danger">删除</button>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script>
<script>
function test() {
console.log('点击了按钮');
}
</script>
</body>
</html>
上面有了布局,按钮,怎么使用网站?
example中有大量网站, 下载实例
后台管理页面: https://getbootstrap.com/docs/4.6/examples/dashboard/
登录页面: https://getbootstrap.com/docs/4.6/examples/sign-in/
下载上面的示例,并找到页面说的名字对应的目录
html <form class="form-signin">
<img class="mb-4" src="../assets/brand/bootstrap-solid.svg" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label for="inputEmail" class="sr-only">Email address</label>
<input type="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="inputPassword" class="form-control" placeholder="Password" required>
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2017-2021</p>
</form>
点了sign in之后,就jquery 发送ajax请求
ES3 标准, 1999年
2008年,iphone, 国外移动互联网,屏幕自适应
ES5 2009年,还使用jquery
ES6 2015.6 前端框架, 将不再使用jquery, 但是底层使用jquery。
jquery包含以下功能:
http://jquery.com/download/ 或CDN
html <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
生产使用min, 减小流量
https://dsf.jb51.net/201406/books/jquery111(jb51.net).rar
1.11.0版本
重点:发ajax请求, 处理响应
操作麻烦
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- #root -->
<div id="root">
<span>内容</span>
</div>
<!-- 原生操作 -->
<script>
// dom, Document Object Model
// window // 浏览器全局对象
// 默认全局对象: window.document document
console.log(document.getElementById('root').innerHTML);
console.log(document.getElementById('root').innerText);
</script>
</body>
</html>
脚本放在前面的问题, dom树还不存在。放在后面就正常
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 原生操作 -->
<script>
// dom, Document Object Model
// window // 浏览器全局对象
// 默认全局对象: window.document document
console.log(document.getElementById('root').innerHTML);
console.log(document.getElementById('root').innerText);
</script>
</head>
<body>
<!-- #root -->
<div id="root">
<span>内容</span>
</div>
</body>
</html>
加载事件, 手工在body放一个事件,前面写函数就正常了。jquery引入就正常。
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 原生操作 -->
<script>
function test() {
// dom, Document Object Model
// window // 浏览器全局对象
// 默认全局对象: window.document document
console.log(document.getElementById('root').innerHTML);
console.log(document.getElementById('root').innerText);
}
</script>
</head>
<body onload="test()">
<!-- #root -->
<div id="root">
<span>内容</span>
</div>
</body>
</html>
解决页面元素加载
选择器 | 标签 |
---|---|
$("p") | <p> |
$('p.intro') | <p class="intro"> |
$('p#demo') | <p id="demo"> |
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<!-- 原生操作 -->
<script>
// $(document).ready(function() {
// // $(document) 相当于选择器,结果变成jquery对象
// // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。
// console.log('页面加载完成');
// });
// 简化版
$(function() {
// 这个就是页面加载完成的回调
console.log(document.getElementById('root')); // 原生对象
console.log(document.getElementById('root').innerHTML); // 原生对象
console.log($(document.getElementById('root')).html()); // 将原生对象包装为jquery对象
console.log($('#root')); // 提供了 init对象, 提供了统一扩音器
console.log('-'.repeat(13));
console.log($('div')); // 选择div元素
console.log($('<div>xyz</div>')); // 包装div标签, 新建div标签,不在dom树中
})
</script>
</head>
<body>
<!-- #root -->
<div id="root">
<span>内容</span>
</div>
</body>
</html>
jquery使用xpath表达式选择带属性的元素
选择器 | 描述 |
---|---|
$('[href]') | 有href属性的所有标签 |
$('[href="#"]') | href="#"的所有标签 |
$('[href!="#"]') | href!="#"的所有标签 |
=".jpg"]') | href以.jpg结尾的所有标签 |
名称 | 描述 |
---|---|
$('').css('key') | 获取css |
$('').css('key', 'value') | 赋值css |
$('').css({'key':'value','key', 'value','key', 'value'}) | 赋值多个css |
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<!-- 原生操作 -->
<script>
// $(document).ready(function() {
// // $(document) 相当于选择器,结果变成jquery对象
// // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。
// console.log('页面加载完成');
// });
// 简化版
$(function() {
const root = $('root')
// 内容变红色
$('#root .content').css('color', 'red')
// .content 前景蓝,背景灰,20px大小
$('.content').css({
'color': 'blue',
'font-size': '20px',
'background-color': '#f0f0f0'
})
const s = $('.content')
// 读取
console.log(s.css('color')); // rgb(0, 0, 255) 蓝色
// 赋值
s.css('margin', '20px')
})
</script>
</head>
<body>
<!-- #root -->
<div id="root">
<span class="content">内容</span>
<span>123</span>
</div>
</body>
</html>
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<!-- 原生操作 -->
<script>
// $(document).ready(function() {
// // $(document) 相当于选择器,结果变成jquery对象
// // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。
// console.log('页面加载完成');
// });
// 简化版
$(function() {
const l = $('span:last-child')
// 取标签和内容 有标签
console.log(l.html()); // 123
// 取内容 无标签
console.log(l.text());
// 修改内容
l.html('123411')
l.html('<a href="#">' + l.html() + '</a>')
})
</script>
</head>
<body>
<!-- #root -->
<div id="root">
<span class="content">内容</span>
<span>
<p>123</p>
</span>
</div>
</body>
</html>
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<!-- 原生操作 -->
<script>
// $(document).ready(function() {
// // $(document) 相当于选择器,结果变成jquery对象
// // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。
// console.log('页面加载完成');
// });
// 简化版
$(function() {
const root = $('#root')
// 子元素 头加一个元素
root.prepend('<div>root 子 header</div><hr/>')
// 子元素 尾加一个元素
root.append('<hr/><div>root 子 footer</div>')
// 添加兄弟
root.after('<div>root 兄弟 after</div>')
root.after($('<div>jquery标签</div>'))
// 内容需要变化
const temp = $('<div/>')
root.append(temp)
temp.html('footer+++++++')
temp.html( temp.html() + 'footer ++++2 ' )
// 添加列表
temp.html(`
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
`)
root.after(`
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
`)
})
</script>
</head>
<body>
<!-- #root -->
<div id="root">
<span class="content">内容</span>
<span>123</span>
</span>
</div>
</body>
</html>
名称 | 描述 |
---|---|
$('').attr('key') | 获取attr |
$('').attr('key', 'value') | 赋值attr |
$('').attr({'key':'value','key', 'value','key', 'value'}) | 赋值多个attr |
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<!-- 原生操作 -->
<script>
// $(document).ready(function() {
// // $(document) 相当于选择器,结果变成jquery对象
// // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。
// console.log('页面加载完成');
// });
// 简化版
$(function() {
// 属性操作
const content = $('.content')
content.append('<img alt="logo" >')
// 添加图片
$('.content img').attr('src', 'http://myapp.image.qiniu.mykernel.cn/favicon.png')
// 获取图片属性
console.log($('.content img').attr('src'));
// 多个属性
$('.content img').attr({
'src': 'http://myapp.image.qiniu.mykernel.cn/favicon.png',
'alt': 'logo',
'width': '100px', // 图片一般修改宽度
})
// click点击事件,再修改也可以
})
</script>
</head>
<body>
<!-- #root -->
<div id="root">
<span class="content">内容</span>
<span>123</span>
</span>
</div>
</body>
</html>
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<!-- 原生操作 -->
<script>
// $(document).ready(function() {
// // $(document) 相当于选择器,结果变成jquery对象
// // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。
// console.log('页面加载完成');
// });
// 简化版
$(function() {
// first 第1个
$('ul li:first').css('color', 'red')
// 奇数变色 odd; 索引0 1 2 3
$('ul li:odd').css('background-color', '#f0f0f0')
// 无论匹配多少个, 首个变色
$('ul li:first').css('color', 'green')
// 父元素匹配多个, 每个父的首个子元素匹配。跨元素匹配首个
$('ul li:first-child').css('background-color', 'black')
// 第几个, 不按索引,接自然数从1开始
$('ul li:nth-child(2)').css('color', 'red')
// 匹配ul父元素中的子元素,有混合类型时,只匹配ul类型的首个元素; 不混合也匹配
$('ul:first-of-type').css({
'border': '1px solid green',
})
// 匹配ul父元素中的子元素,只有单一类型时, 只匹配ul类型的首个元素
$('ul:first-child').css({
'border': '1px solid blue',
})
})
</script>
</head>
<body>
<!-- #root -->
<div id="root">
<span class="content">内容</span>
<span>123</span>
</span>
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
<div>
<ul>
<li>e</li>
<li>f</li>
<li>g</li>
</ul>
<ul>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>
</div>
</body>
</html>
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<!-- 原生操作 -->
<script>
// $(document).ready(function() {
// // $(document) 相当于选择器,结果变成jquery对象
// // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。
// console.log('页面加载完成');
// });
// 简化版
$(function() {
// 隐藏123
console.log( $('span:nth-of-type(2)'));
// 隐藏
$('span:nth-of-type(2)').css('display','none')
// 显示
$('span:nth-of-type(2)').css('display', '')
// 转换块
$('span:nth-of-type(2)').css('display', 'block')
// $('#root').css('display', 'none')
// $('#root').css('height', '100px')
// $('#root').css('width', '100px')
})
</script>
</head>
<body>
<!-- #root -->
<div id="root">
<span class="content">内容</span>
<span>123</span>
</span>
</div>
</body>
</html>
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<!-- 原生操作 -->
<script>
// $(document).ready(function() {
// // $(document) 相当于选择器,结果变成jquery对象
// // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。
// console.log('页面加载完成');
// });
// 简化版
$(function() {
})
// 原始写法
function test() {
console.log('点击 了test');
}
</script>
</head>
<body>
<!-- #root -->
<div id="root">
<span class="content" onclick="test()">请点击我</span>
<span>123</span>
</span>
</div>
</body>
</html>
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<!-- 原生操作 -->
<script>
// $(document).ready(function() {
// // $(document) 相当于选择器,结果变成jquery对象
// // jquery对象变成一个方法 ready,相当于load; 当前函数就是回调,就是事件满足时,就触发的函数。
// console.log('页面加载完成');
// });
// 简化版
$(function() {
let count = 1
$('.content').click(function(event) {
console.log(event,'~'.repeat(12));
// event.target事件中包含了你产生此事件(click)的对象 <span class="content">请点击我</span>
console.log(event.target);
// 每点一次,在控制台中输出信息
let e = $('<div>' + count++ + '</div>')
e.css({
'margin-bottom': '5px',
'border': '1px solid #ccc',
})
$('.console').append(e)
})
})
</script>
</head>
<body>
<!-- #root -->
<div id="root">
<span class="content" >请点击我</span>
<span>123</span>
</span>
</div>
<div class="console">
</div>
</body>
</html>
优化,每次添加css, 每个添加的元素加一个类,style中统一定css
diff // 每点一次,在控制台中输出信息
+ let e = $('<div class="card">' + count++ + '</div>')
$('.console').append(e)
})
})
</script>
+ <style>
.card {
margin-bottom: 5px;
border: 1px solid #ccc;
}
</style>
jQuery对XMLHttpRequest组件的调用接口实现了封闭,更加方便调用。默认异步请求
解决的问题:同步请求,每一个点击,整个页面需要刷新。注册时, 如果用户提交时,页面提交时页面卡住, 服务端发现用户名冲突,需要用户再次请求注册,用户会重新刷新,刷新后用户提交的信息会丢失,体验差。2005之后,ajax出现异步ajax请求,异步获取xml, 后来使用json, 比xml更有效的承载数据。而名字保留下来。Ajax技术
salary/urls.py
python"""salary URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse
from django.shortcuts import render
def index(request: HttpResponse):
return render(request, template_name='index.html', context={"test": 'how are you?'})
# 主路由
urlpatterns = [
path('admin/', admin.site.urls),
path('emp/', include('employee.urls')), # 2级路由一定要/
path('', index)
]
templates/index.html
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板测试文件</title>
</head>
<body>
{{ test }}
</body>
</html>
salary/urls.py
pythonfrom django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse
from django.shortcuts import render
from django.conf import settings # django的配置文件封装的对象
def index(request: HttpResponse):
print('*'*30)
print(*filter(lambda x:x[0].startswith('STATIC'),settings.__dict__.items()),sep='\n')
# ('STATIC_URL', '/static/')
# ('STATICFILES_FINDERS',
# ['django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder'])
# ('STATICFILES_DIRS', []) # FileSystemFinder中, 找到返回,没有找到继续找,找完就 继续通过 AppDirectoriesFinder在注册的app中static子目录查找 。
print('*'*30)
return render(request, template_name='index.html', context={"test": 'how are you?'})
# 主路由
urlpatterns = [
path('admin/', admin.site.urls),
path('emp/', include('employee.urls')), # 2级路由一定要/
path('', index)
]
salary/settings.py
python# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'testst']
准备jquery下载文件
powershellinvoke-webrequest https://code.jquery.com/jquery-3.6.0.min.js -outfile D:\py_projects\djangoT39\testst\js\jquery-3.6.0.min.js
templates/index.html
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板测试文件</title>
<script src="/static/js/jquery-3.6.0.min.js"></script>
</head>
<body>
{{ test }}
</body>
</html>
访问http://127.0.0.1:8000/static/js/jquery-3.6.0.min.js
正常
不手工写死路径 /static/js/jquery-3.6.0.min.js
只写static 加逻辑路径
html
<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板测试文件</title>
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
</head>
<body>
{{ test }}
</body>
</html>
templates/index.html
html<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板测试文件</title>
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
</head>
<body>
{{ test }}
<app id="root">
<button class="ajaxget">
Ajax Get
</button>
</app>
<script>
// 页面加载完执行
$(function () {
$('.ajaxget').click(function (event) {
console.log(event.target, '~'.repeat(30));
// /testget => http://127.0.0.1:8000/testget 直接从/起始
// testget => http://127.0.0.1:8000/testget 相对当前起始
$.get("/testget?a=1&b=2&b=3", function (data) {
console.log(data, '~'.repeat(50));
});
})
})
</script>
</body>
</html>
$.get(路径, 成功回调)
, 失败就异常。salary/urls.py
pythonfrom django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse, HttpRequest, JsonResponse
from django.shortcuts import render
from django.conf import settings # django的配置文件封装的对象
def index(request: HttpRequest):
return render(request, template_name='index.html', context={"test": 'how are you?'})
def test_get(request: HttpRequest):
print('*'*30)
print(request.method)
print(request.content_type)
print(request.GET) # 查询字符串, 多值字典
print()
print('*'*30)
return JsonResponse({'books': [
(1,'python', 20),
(2,'go', 5),
]})
# 主路由
urlpatterns = [
path('admin/', admin.site.urls),
path('emp/', include('employee.urls')), # 2级路由一定要/
path('index', index), # 主页
path('testget', test_get), # 按钮get
]
用户点按钮之后
pycharm中返回
python******************************
GET
text/plain
<QueryDict: {'a': ['1'], 'b': ['2', '3']}>
******************************
[05/May/2022 16:44:26] "GET /testget?a=1&b=2&b=3 HTTP/1.1" 200 44
在ajax中,查询 参数也可以使用以下方式传递,但是后端返回
js$.get("/testget", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); });
pythonGET text/plain <QueryDict: {'a': ['1'], 'b': ['3']}>
当使用map传递时,相同key的值就只会有1个
当替换上面的get请求的路径为 http://localhost/testget
templates/index.html
html<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板测试文件</title>
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
</head>
<body>
{{ test }}
<app id="root">
<button class="ajaxget">
Ajax Get
</button>
<button class="ajaxgetcors">
Ajax Get 跨域请求
</button>
</app>
<script>
// 页面加载完执行
$(function () {
$('.ajaxget').click(function (event) {
console.log(event.target, '~'.repeat(30));
// /testget => http://127.0.0.1:8000/testget 直接从/起始
// testget => http://127.0.0.1:8000/testget 相对当前起始
$.get("/testget", {a: 1, b: 2, b:3},function (data) {
console.log(data, '~'.repeat(50));
});
})
$('.ajaxgetcors').click(function (event) {
console.log(event.target, '~'.repeat(30));
$.get("http://localhost:8000/testget", {a: 1, b: 2, b:3},function (data) {
console.log(data, '~'.repeat(50));
});
})
})
</script>
</body>
</html>
返回结果
而后端响应是200, 说明浏览器拿到数据,但是数据扔了
python******************************
GET
text/plain
<QueryDict: {'a': ['1'], 'b': ['3']}>
******************************
[05/May/2022 17:07:20] "GET /testget?a=1&b=3 HTTP/1.1" 200 44
后端代码salary/urls.py
difffrom django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse, HttpRequest, JsonResponse
from django.shortcuts import render
from django.conf import settings # django的配置文件封装的对象
def index(request: HttpRequest):
return render(request, template_name='index.html', context={"test": 'how are you?'})
def test_get(request: HttpRequest):
print('*'*30)
print(request.method)
print(request.content_type)
print(request.GET) # 查询字符串, 多值字典
print()
print('*'*30)
res = JsonResponse({'books': [
(1,'python', 20),
(2,'go', 5),
]})
+ res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
+ return res
# 主路由
urlpatterns = [
path('admin/', admin.site.urls),
path('emp/', include('employee.urls')), # 2级路由一定要/
path('index', index), # 主页
path('testget', test_get), # 按钮get
]
这个上面是仅允许http://127.0.0.1:8000 域。如果想任何源站访问时,均允许, 将值修改为'*'
templates/index.html
<!DOCTYPE html> {% load static %} <html lang="en"> <head> <meta charset="UTF-8"> <title>模板测试文件</title> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> </head> <body> {{ test }} <app id="root"> <button class="ajaxget"> Ajax Get </button> <button class="ajaxgetcors"> Ajax Get 跨域请求 </button> <button class="ajaxpost"> Ajax POST 请求 </button> </app> <script> // 页面加载完执行 $(function () { $('.ajaxget').click(function (event) { console.log(event.target, '~'.repeat(30)); // /testget => http://127.0.0.1:8000/testget 直接从/起始 // testget => http://127.0.0.1:8000/testget 相对当前起始 $.get("/testget", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxgetcors').click(function (event) { console.log(event.target, '~'.repeat(30)); $.get("http://localhost:8000/testget", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxpost').click(function (event) { console.log(event.target, '~'.repeat(30)); // http://127.0.0.1:8000/testget post用请求报文的body上传数据,不需要查询参数 $.post("/testpost", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) }) </script> </body> </html>
salary/urls.py
"""salary URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/3.2/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) # GET POST 所有method请求 def test_get(request: HttpRequest): print('*'*30) print(request.method) print(request.content_type) print(request.GET) # 查询字符串, 多值字典 print() print('*'*30) res = JsonResponse({'books': [ (1,'python', 20), (2,'go', 5), ]}) res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' return res def test_post(request: HttpRequest): print('+'*30) print(request.method) print(request.content_type) print(request.GET) # 查询字符串, 多值字典 print(request.POST) # 查询字符串, 多值字典 print() print('+'*30) res = JsonResponse({'books': [ (1,'python', 20), ]}) # res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' return res # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('testget', test_get), # 按钮get path('testpost', test_post), # 按钮get ]
请求时响应
pythonForbidden (CSRF cookie not set.): /testget
Forbidden (CSRF cookie not set.): /testget
[05/May/2022 17:20:25] "POST /testget HTTP/1.1" 403 2801
取消此中间件 salary/settings.py
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
++++++++++++++++++++++++++++++ POST application/x-www-form-urlencoded <QueryDict: {}> <QueryDict: {'a': ['1'], 'b': ['3']}> ++++++++++++++++++++++++++++++
templates/index.html
<!DOCTYPE html> {% load static %} <html lang="en"> <head> <meta charset="UTF-8"> <title>模板测试文件</title> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> </head> <body> {{ test }} <app id="root"> <button class="ajaxget"> Ajax Get </button> <button class="ajaxgetcors"> Ajax Get 跨域请求 </button> <button class="ajaxpost"> Ajax POST 请求 </button> <button class="ajaxpostcors"> Ajax POST 跨域请求 </button> </app> <script> // 页面加载完执行 $(function () { $('.ajaxget').click(function (event) { console.log(event.target, '~'.repeat(30)); // /testget => http://127.0.0.1:8000/testget 直接从/起始 // testget => http://127.0.0.1:8000/testget 相对当前起始 $.get("/testget", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxgetcors').click(function (event) { console.log(event.target, '~'.repeat(30)); $.get("http://localhost:8000/testget", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxpost').click(function (event) { console.log(event.target, '~'.repeat(30)); // http://127.0.0.1:8000/testpost post用请求报文的body上传数据,不需要查询参数 $.post("/testpost", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) $('.ajaxpostcors').click(function (event) { console.log(event.target, '~'.repeat(30)); // http://127.0.0.1:8000/testpost post用请求报文的body上传数据,不需要查询参数 $.post("http://localhost:8000/testpost?k1=v1&k2=v2", {a: 1, b: 2, b:3},function (data) { console.log(data, '~'.repeat(50)); }); }) }) </script> </body> </html>
同样会报错,以下解决
salary/urls.py
difffrom django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse, HttpRequest, JsonResponse
from django.shortcuts import render
from django.conf import settings # django的配置文件封装的对象
def index(request: HttpRequest):
return render(request, template_name='index.html', context={"test": 'how are you?'})
# GET POST 所有method请求
def test_get(request: HttpRequest):
print('*'*30)
print(request.method)
print(request.content_type)
print(request.GET) # 查询字符串, 多值字典
print()
print('*'*30)
res = JsonResponse({'books': [
(1,'python', 20),
(2,'go', 5),
]})
res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
return res
def test_post(request: HttpRequest):
print('+'*30)
print(request.method)
print(request.content_type)
print(request.GET) # 查询字符串, URL 中
print(request.POST) # 查询字符串, 多值字典. 请求报文的body
print()
print('+'*30)
res = JsonResponse({'books': [
(1,'python', 20),
]})
+ res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
return res
# 主路由
urlpatterns = [
path('admin/', admin.site.urls),
path('emp/', include('employee.urls')), # 2级路由一定要/
path('index', index), # 主页
path('testget', test_get), # 按钮get
path('testpost', test_post), # 按钮get
]
每个接口均需要配置跨域的首部
salary/urls.py
python"""salary URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse, HttpRequest, JsonResponse
from django.shortcuts import render
from django.conf import settings # django的配置文件封装的对象
def index(request: HttpRequest):
return render(request, template_name='index.html', context={"test": 'how are you?'})
# GET POST 所有method请求
def test_get(request: HttpRequest):
print('*'*30)
print(request.method)
print(request.content_type)
print(request.GET) # 查询字符串, 多值字典
print()
print('*'*30)
res = JsonResponse({'books': [
(1,'python', 20),
(2,'go', 5),
]})
res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
return res
def test_post(request: HttpRequest):
print('+'*30)
print(request.method)
print(request.content_type)
print(request.GET) # 查询字符串, URL 中
print(request.POST) # 查询字符串, 多值字典. 此方法对应 application/x-www-form-urlencoded 和 multipart/form-data 传统表单方法
print()
print('+'*30)
res = JsonResponse({'books': [
(1,'python', 20),
]})
res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
return res
def test_json(request: HttpRequest):
"""
json请求时,跨域时,会出现预检请求
OPTIONS
text/plain
<QueryDict: {'k': ['5'], 'v': ['6']}>
<QueryDict: {}>
False
b''
"""
print('+'*30)
print(request.method) # application/json
print(request.content_type)
print(request.GET) # 查询字符串, URL 中
print(request.POST) # 虽然post请求,但是我们发的内容类型是application/json; 此方法对应 application/x-www-form-urlencoded 和 multipart/form-data 传统表单方法
print(request.is_ajax()) # True
print(request.body) # json从这里提取,没有flask的json属性
print('+'*30)
res = JsonResponse({'books': [
(1,'c++', 20000),
]})
res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
res.headers['Access-Control-Allow-Headers'] = 'content-type'
return res
# 主路由
urlpatterns = [
path('admin/', admin.site.urls),
path('emp/', include('employee.urls')), # 2级路由一定要/
path('index', index), # 主页
path('testget', test_get), # 按钮get
path('testpost', test_post), # 按钮get
path('testjson', test_json), # 按钮post
]
templates/index.html
html<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板测试文件</title>
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
</head>
<body>
{{ test }}
<app id="root">
<h1>简单请求</h1>
<button class="ajaxget">
Ajax Get
</button>
<button class="ajaxgetcors">
Ajax Get 跨域请求
</button>
<button class="ajaxpost">
Ajax POST 请求
</button>
<button class="ajaxpostcors">
Ajax POST 跨域请求
</button>
<h1>json 预检请求</h1>
<button class="ajaxjson">Ajax POST json 同域请求, 同域不出现预检</button>
<button class="ajaxjsoncors">Ajax POST json 跨域请求</button>
</app>
<script>
// 页面加载完执行
$(function () {
$('.ajaxget').click(function (event) {
console.log(event.target, '~'.repeat(30));
// /testget => http://127.0.0.1:8000/testget 直接从/起始
// testget => http://127.0.0.1:8000/testget 相对当前起始
$.get("/testget", { a: 1, b: 2, b: 3 }, function (data) {
console.log(data, '~'.repeat(50));
});
})
$('.ajaxgetcors').click(function (event) {
console.log(event.target, '~'.repeat(30));
$.get("http://localhost:8000/testget", { a: 1, b: 2, b: 3 }, function (data) {
console.log(data, '~'.repeat(50));
});
})
$('.ajaxpost').click(function (event) {
console.log(event.target, '~'.repeat(30));
// http://127.0.0.1:8000/testpost post用请求报文的body上传数据,不需要查询参数
$.post("/testpost", { a: 1, b: 2, b: 3 }, function (data) {
console.log(data, '~'.repeat(50));
});
})
$('.ajaxpostcors').click(function (event) {
console.log(event.target, '~'.repeat(30));
// http://127.0.0.1:8000/testpost post用请求报文的body上传数据,不需要查询参数
$.post("http://localhost:8000/testpost?k1=v1&k2=v2", { a: 1, b: 2, b: 3 }, function (data) {
console.log(data, '~'.repeat(50));
});
})
// 同域不出现预检
$('.ajaxjson').click(function (event) {
console.log(event.target, '~'.repeat(30));
// http://127.0.0.1:8000/testjson post用请求报文的body上传数据,不需要查询参数
// 简单格式, 只支持 application/x-www-form-urlencoded
// $.post("/testjson?k=5&v=6", { a: 1, b: 2, b: 3 }, function (data) {
// console.log(data, '~'.repeat(50));
// });
// 原生格式使用请求体的内容类型 application/json
$.ajax({
type: "POST",
url: "/testjson?k=5&v=6",
contentType: "application/json",
data: { a: 1, b: 2, b: 3 },
success: function (msg) {
console.log(msg, '+'.repeat(50));
}, // 成功回调
});
})
$('.ajaxjsoncors').click(function (event) {
console.log(event.target, '~'.repeat(30));
// http://127.0.0.1:8000/testjson post用请求报文的body上传数据,不需要查询参数
// 简单格式, 只支持 application/x-www-form-urlencoded
// $.post("/testjson?k=5&v=6", { a: 1, b: 2, b: 3 }, function (data) {
// console.log(data, '~'.repeat(50));
// });
// 原生格式使用请求体的内容类型 application/json
$.ajax({
type: "POST",
url: "http://localhost:8000/testjson?k=5&v=6",
contentType: "application/json", // MIME 类型
data: { a: 1, b: 2, b: 3 },
success: function (msg) {
console.log(msg, '+'.repeat(50));
}, // 成功回调
});
})
})
</script>
</body>
</html>
当点击 Ajax POST json 跨域请求, 会出现2个请求, 第1是预检请求。会拿着和用户请求的URL+查询字符串,和Access-Control-Request-* 请求服务器
python++++++++++++++++++++++++++++++
OPTIONS
text/plain
<QueryDict: {'k': ['5'], 'v': ['6']}>
<QueryDict: {}>
False
b''
++++++++++++++++++++++++++++++
[06/May/2022 09:13:03] "OPTIONS /testjson?k=5&v=6 HTTP/1.1" 200 30
服务器收到的请求方法是 OPTIONS, 请求的类型是 text/plain , 查询 字符存在,不是ajax请求,表单请求体为空,此请求需要响应OK,才可以进行后续的请求
python++++++++++++++++++++++++++++++
POST
application/json
<QueryDict: {'k': ['5'], 'v': ['6']}>
<QueryDict: {}>
False
b'a=1&b=3'
++++++++++++++++++++++++++++++
[06/May/2022 09:13:03] "POST /testjson?k=5&v=6 HTTP/1.1" 200 30
服务器收到POST, 请求体的类型是 application/json ,查询字符,表单请求体为空, 不是ajax请求, 请求体存在
print(request.body)
b'a=1&b=3' 这个给表单方法处理
这个问题是发数据的问题
diff<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板测试文件</title>
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
</head>
<body>
{{ test }}
<app id="root">
<h1>简单请求</h1>
<button class="ajaxget">
Ajax Get
</button>
<button class="ajaxgetcors">
Ajax Get 跨域请求
</button>
<button class="ajaxpost">
Ajax POST 请求
</button>
<button class="ajaxpostcors">
Ajax POST 跨域请求
</button>
<h1>json 预检请求</h1>
<button class="ajaxjson">Ajax POST json 同域请求, 同域不出现预检</button>
<button class="ajaxjsoncors">Ajax POST json 跨域请求</button>
</app>
<script>
// 页面加载完执行
$(function () {
$('.ajaxget').click(function (event) {
console.log(event.target, '~'.repeat(30));
// /testget => http://127.0.0.1:8000/testget 直接从/起始
// testget => http://127.0.0.1:8000/testget 相对当前起始
$.get("/testget", { a: 1, b: 2, b: 3 }, function (data) {
console.log(data, '~'.repeat(50));
});
})
$('.ajaxgetcors').click(function (event) {
console.log(event.target, '~'.repeat(30));
$.get("http://localhost:8000/testget", { a: 1, b: 2, b: 3 }, function (data) {
console.log(data, '~'.repeat(50));
});
})
$('.ajaxpost').click(function (event) {
console.log(event.target, '~'.repeat(30));
// http://127.0.0.1:8000/testpost post用请求报文的body上传数据,不需要查询参数
$.post("/testpost", { a: 1, b: 2, b: 3 }, function (data) {
console.log(data, '~'.repeat(50));
});
})
$('.ajaxpostcors').click(function (event) {
console.log(event.target, '~'.repeat(30));
// http://127.0.0.1:8000/testpost post用请求报文的body上传数据,不需要查询参数
$.post("http://localhost:8000/testpost?k1=v1&k2=v2", { a: 1, b: 2, b: 3 }, function (data) {
console.log(data, '~'.repeat(50));
});
})
// 同域不出现预检
$('.ajaxjson').click(function (event) {
console.log(event.target, '~'.repeat(30));
// http://127.0.0.1:8000/testjson post用请求报文的body上传数据,不需要查询参数
// 简单格式, 只支持 application/x-www-form-urlencoded
// $.post("/testjson?k=5&v=6", { a: 1, b: 2, b: 3 }, function (data) {
// console.log(data, '~'.repeat(50));
// });
// 原生格式使用请求体的内容类型 application/json
$.ajax({
type: "POST",
url: "/testjson?k=5&v=6",
contentType: "application/json",
+ data: JSON.stringify({ a: 1, b: 2, b: 3 }), // javascript内建对象JSON
success: function (msg) {
console.log(msg, '+'.repeat(50));
}, // 成功回调
});
})
$('.ajaxjsoncors').click(function (event) {
console.log(event.target, '~'.repeat(30));
// http://127.0.0.1:8000/testjson post用请求报文的body上传数据,不需要查询参数
// 简单格式, 只支持 application/x-www-form-urlencoded
// $.post("/testjson?k=5&v=6", { a: 1, b: 2, b: 3 }, function (data) {
// console.log(data, '~'.repeat(50));
// });
// 原生格式使用请求体的内容类型 application/json
$.ajax({
type: "POST",
url: "http://localhost:8000/testjson?k=5&v=6",
contentType: "application/json", // MIME 类型
+ data: JSON.stringify({ a: 1, b: 2, b: 3 }), // javascript内建对象JSON
success: function (msg) {
console.log(msg, '+'.repeat(50));
}, // 成功回调
});
})
})
</script>
</body>
</html>
现在python拿到的数据
python++++++++++++++++++++++++++++++
POST
application/json
<QueryDict: {'k': ['5'], 'v': ['6']}>
<QueryDict: {}>
False
b'{"a":1,"b":3}'
++++++++++++++++++++++++++++++
现在可以处理了, option方法请求时,请求体是空的,post方法才有值,才可以转成字典
diff"""salary URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse, HttpRequest, JsonResponse
from django.shortcuts import render
from django.conf import settings # django的配置文件封装的对象
def index(request: HttpRequest):
return render(request, template_name='index.html', context={"test": 'how are you?'})
# GET POST 所有method请求
def test_get(request: HttpRequest):
print('*' * 30)
print(request.method)
print(request.content_type)
print(request.GET) # 查询字符串, 多值字典
print()
print('*' * 30)
res = JsonResponse({'books': [
(1, 'python', 20),
(2, 'go', 5),
]})
res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
return res
def test_post(request: HttpRequest):
print('+' * 30)
print(request.method)
print(request.content_type)
print(request.GET) # 查询字符串, URL 中
print(request.POST) # 查询字符串, 多值字典. 请求报文的body
print()
print('+' * 30)
res = JsonResponse({'books': [
(1, 'python', 20),
]})
res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
return res
def test_json(request: HttpRequest):
"""
json请求时,跨域时,会出现预检请求
OPTIONS
text/plain
<QueryDict: {'k': ['5'], 'v': ['6']}>
<QueryDict: {}>
False
b''
真正请求,返回 b'a=1&b=3'
返回bytes
"""
print('+' * 30)
print(request.method)
print(request.content_type) # application/json
print(request.GET) # 查询字符串, URL 中
print(
request.POST) # 但是post请求,但是我们发的内容类型是application/json; 此方法对应 application/x-www-form-urlencoded 和 application/form-data 传统表单方法
print(request.is_ajax()) # True
print(request.body) # json从这里提取,没有flask的json属性; b'a=1&b=3' 这个给表单方法处理
+ if request.method == "POST":
+ import json
+ print(json.loads(request.body), '&0' * 30) # {'a': 1, 'b': 3}
print('+' * 30)
res = JsonResponse({'books': [
(1, 'c++', 20000),
]})
res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
res.headers['Access-Control-Allow-Headers'] = 'content-type'
return res
# 主路由
urlpatterns = [
path('admin/', admin.site.urls),
path('emp/', include('employee.urls')), # 2级路由一定要/
path('index', index), # 主页
path('testget', test_get), # 按钮get
path('testpost', test_post), # 按钮get
path('testjson', test_json), # 按钮get
]
Ajax方法,提交GET。从服务器返回数据,使用表格显示,要求使用JS对表格动态追加。
salary/urls.py
python
from django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse, HttpRequest, JsonResponse
from django.shortcuts import render
from django.conf import settings # django的配置文件封装的对象
def index(request: HttpRequest):
return render(request, template_name='index.html', context={"test": 'how are you?'})
def test(request:HttpRequest):
return render(request,template_name='test.html',context={'name': 'mykernel'})
# 主路由
urlpatterns = [
path('admin/', admin.site.urls),
path('emp/', include('employee.urls')), # 2级路由一定要/
path('index', index), # 主页
path('test', test), # 主页
]
templates/test.html
<!DOCTYPE html> {% load static %} <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> <style> .console { padding-top: 22px; } table, tr, td,th { border-collapse: collapse; border: 1px solid black; } </style> </head> <body> <h1>{{ name|add:".cn" }}</h1> <button>GET动态添加表格</button> <div class="console"> <table> <tr> <th>序号</th> <th>书名</th> <th>数量</th> </tr> </table> </div> <script> $(function() { $('button').click(function() { console.log('click'); $('.console table').append(` <tr> <td>1</td> <td>2</td> <td>3</td> </tr> `) }) }) </script> </body> </html>
点击按钮,动态添加表格
templates/test.html
<!DOCTYPE html> {% load static %} <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> <style> .console { padding-top: 22px; } table, tr, td, th { border-collapse: collapse; border: 1px solid black; } </style> </head> <body> <h1>{{ name|add:".cn" }}</h1> <button>GET动态添加表格</button> <div class="console"> <table> <tr> <th>序号</th> <th>书名</th> <th>数量</th> </tr> </table> </div> <script> $(function () { $('button').click(function () { $.ajax({ type: "POST", url: "http://localhost:8000/testjson", contentType: "application/json", data: JSON.stringify({a:1,b:2,c:3}), success: function (msg) { console.log(msg,'+'.repeat(30)); } }); $('.console table').append(` <tr> <td>1</td> <td>2</td> <td>3</td> </tr> `) }) }) </script> </body> </html>
salary/urls.py
from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) def test(request:HttpRequest): return render(request,template_name='test.html',context={'name': 'mykernel'}) def test_json(request:HttpRequest): print(request.method) # OPTION -> POST print(request.content_type) # text/plain -> application/json print(request.GET) print(request.POST) print(request.body) # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('test', test), # 主页 path('testjson', test_json), # application/json请求 ]
from django.contrib import admin from django.urls import path, include from django.http import HttpResponse, HttpRequest, JsonResponse from django.shortcuts import render from django.conf import settings # django的配置文件封装的对象 def index(request: HttpRequest): return render(request, template_name='index.html', context={"test": 'how are you?'}) def test(request:HttpRequest): return render(request,template_name='test.html',context={'name': 'mykernel'}) def test_json(request:HttpRequest): print(request.method) # OPTION -> POST print(request.content_type) # text/plain -> application/json print(request.GET) print(request.POST) print(request.body) # 主路由 urlpatterns = [ path('admin/', admin.site.urls), path('emp/', include('employee.urls')), # 2级路由一定要/ path('index', index), # 主页 path('test', test), # 主页 path('testjson', test_json), # application/json请求 ]
python
from django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse, HttpRequest, JsonResponse
from django.shortcuts import render
from django.conf import settings # django的配置文件封装的对象
def index(request: HttpRequest):
return render(request, template_name='index.html', context={"test": 'how are you?'})
def test(request:HttpRequest):
return render(request,template_name='test.html',context={'name': 'mykernel'})
def test_json(request:HttpRequest):
print(request.method) # OPTION -> POST
print(request.content_type) # text/plain -> application/json
print(request.GET)
print(request.POST)
print(request.body)
return JsonResponse({
'books': [
(1,'c',10),
(2,'c++',11),
(3,'python',200),
(4,'go',2),
]
})
# 主路由
urlpatterns = [
path('admin/', admin.site.urls),
path('emp/', include('employee.urls')), # 2级路由一定要/
path('index', index), # 主页
path('test', test), # 主页
path('testjson', test_json), # application/json请求
]
现在预检不正常,是CORS 错误了,所以需要跨域首部就是 预检的 Access-Control-Request-* 这些添加到后端
Access-Control-Request-Headers: content-type Access-Control-Request-Method: POST
控制台有配置方法 Access-Control-Allow-Origin 和orgin后面的地址添加到后端
test:1 Access to XMLHttpRequest at 'http://localhost:8000/testjson' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. jquery-3.6.0.min.js:2 POST http://localhost:8000/testjson net::ERR_FAILED
添加 Access-Control-Allow-Headers 和 Request header field content-type
Access to XMLHttpRequest at 'http://localhost:8000/testjson' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response. jquery-3.6.0.min.js:2 POST http://localhost:8000/testjson net::ERR_FAILED
salary/urls.py
python
from django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse, HttpRequest, JsonResponse
from django.shortcuts import render
from django.conf import settings # django的配置文件封装的对象
def index(request: HttpRequest):
return render(request, template_name='index.html', context={"test": 'how are you?'})
def test(request:HttpRequest):
return render(request,template_name='test.html',context={'name': 'mykernel'})
def test_json(request:HttpRequest):
print(request.method) # OPTION -> POST
print(request.content_type) # text/plain -> application/json
print(request.GET)
print(request.POST)
print(request.body)
res = JsonResponse({
'books': [
(1,'c',10),
(2,'c++',11),
(3,'python',200),
(4,'go',2),
]
})
res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
res.headers['Access-Control-Allow-Headers'] = 'CONTENT-TYPE'
return res
# 主路由
urlpatterns = [
path('admin/', admin.site.urls),
path('emp/', include('employee.urls')), # 2级路由一定要/
path('index', index), # 主页
path('test', test), # 主页
path('testjson', test_json), # application/json请求
]
templates/test.html
html<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<style>
.console {
padding-top: 22px;
}
table,
tr,
td,
th {
border-collapse: collapse;
border: 1px solid black;
}
</style>
</head>
<body>
<h1>{{ name|add:".cn" }}</h1>
<button>GET动态添加表格</button>
<div class="console">
<table>
<tr>
<th>序号</th>
<th>书名</th>
<th>数量</th>
</tr>
</table>
</div>
<script>
$(function () {
$('button').click(function () {
$.ajax({
type: "POST",
url: "http://localhost:8000/testjson",
contentType: "application/json",
data: JSON.stringify({ a: 1, b: 2, c: 3 }),
success: function (msg) {
console.log(msg, '+'.repeat(30));
let books = msg.books
for (let book of books) {
// console.log(book);
let [id, book_name, nums] = book
$('.console table').append(`
<tr>
<td>${id}</td>
<td>${book_name}</td>
<td>${nums}</td>
</tr>
`)
}
}
});
})
})
</script>
</body>
</html>
上面的跨域,是网站写的代码决定的,跟用户没有关系。如果你写的后台,后台需要解决这个问题。
解决跨域的方法
如果第3方人家请求你,你允许他,你就需要解决跨域问题。如果你访问第3方后台接口(阿里, 腾讯),他需要解决,他不一定需要修改代码,可以使用jsonp。
jsonp调用第3方接口常用方式
<img> <link> <script>
等标签, GET方法可以使用不同域的文件
例如:获取天气网站数据,GET请求数据;一般是jsonp接口。协议要点,允许 用户传递callback参数给服务端,服务端将数据传递给callback函数,之后你在本地的此函数中提供数据即可。
devops\index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="static/js/my.js"></script> </head> <body> <script> console.log(x); </script> </body> </html>
devops\static\js\my.js
const x = 'abc1x'
visual code 的 live server 插件 浏览index.html
可以看到打印的值
http://127.0.0.1:8000/static/js/my.js
修改 devops\index.html
diff<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
+ <script src="http://127.0.0.1:8000/static/js/my.js"></script>
</head>
<body>
<script>
console.log(x);
</script>
</body>
</html>
一般我们项目开发,静态文件,使用CDN路径。以下3个标签均是GET请求, 可以跨域。
htmllink
script
img <!-- 防盗链 -->
服务端不需要做任何改动, 客户端正常访问
salary/urls.py
python
from django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse, HttpRequest, JsonResponse
from django.shortcuts import render
from django.conf import settings # django的配置文件封装的对象
def index(request: HttpRequest):
return render(request, template_name='index.html', context={"test": 'how are you?'})
def test(request:HttpRequest):
return render(request,template_name='test.html',context={'name': 'mykernel'})
def test_json(request:HttpRequest):
print(request.method) # OPTION -> POST
print(request.content_type) # text/plain -> application/json
print(request.GET)
print(request.POST)
print(request.body)
res = JsonResponse({
'books': [
(1,'c',10),
(2,'c++',11),
(3,'python',200),
(4,'go',2),
]
})
res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
res.headers['Access-Control-Allow-Headers'] = 'CONTENT-TYPE'
return res
def test_script(request:HttpRequest):
return HttpResponse("const x = 'fffhelo'",content_type='application/javascript')
# 主路由
urlpatterns = [
path('admin/', admin.site.urls),
path('emp/', include('employee.urls')), # 2级路由一定要/
path('index', index), # 主页
path('test', test), # 主页
path('testjson', test_json), # application/json请求
path('testscript', test_script), # GET
]
注意,返回MIME类型为
application/javascript
devops\index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="http://127.0.0.1:8000/testscript"></script> </head> <body> <script> console.log(x); </script> </body> </html>
devops\index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> function t123(data) { console.log(data, '^'.repeat(5)); } </script> <script src="http://127.0.0.1:8000/testscript"></script> </body> </html>
salary/urls.py
pythonfrom django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse, HttpRequest, JsonResponse
from django.shortcuts import render
from django.conf import settings # django的配置文件封装的对象
def index(request: HttpRequest):
return render(request, template_name='index.html', context={"test": 'how are you?'})
def test(request: HttpRequest):
return render(request, template_name='test.html', context={'name': 'mykernel'})
def test_json(request: HttpRequest):
print(request.method) # OPTION -> POST
print(request.content_type) # text/plain -> application/json
print(request.GET)
print(request.POST)
print(request.body)
res = JsonResponse({
'books': [
(1, 'c', 10),
(2, 'c++', 11),
(3, 'python', 200),
(4, 'go', 2),
]
})
res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
res.headers['Access-Control-Allow-Headers'] = 'CONTENT-TYPE'
return res
def test_script(request: HttpRequest):
text = """
t123({a:100, b: 'abcd'})
"""
return HttpResponse(text, content_type='application/javascript')
# 主路由
urlpatterns = [
path('admin/', admin.site.urls),
path('emp/', include('employee.urls')), # 2级路由一定要/
path('index', index), # 主页
path('test', test), # 主页
path('testjson', test_json), # application/json请求
path('testscript', test_script), # GET
]
注意:这里
t123({a:100, b: 'abcd'})
就是远程的对象script标签可以跨域发GET请求
pythonimport json def test_script(request: HttpRequest): text = """t123({})""".format(json.dumps({'a':111100, 'b': 'abcd'})) # 查了数据库 return HttpResponse(text, content_type='application/javascript')
devops\index.html
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function t234(data) {
console.log(data, '^'.repeat(5));
}
</script>
<script src="http://127.0.0.1:8000/testscript?callback=t234"></script>
</body>
</html>
salary/urls.py
pythonfrom django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse, HttpRequest, JsonResponse
from django.shortcuts import render
from django.conf import settings # django的配置文件封装的对象
def index(request: HttpRequest):
return render(request, template_name='index.html', context={"test": 'how are you?'})
def test(request: HttpRequest):
return render(request, template_name='test.html', context={'name': 'mykernel'})
def test_json(request: HttpRequest):
print(request.method) # OPTION -> POST
print(request.content_type) # text/plain -> application/json
print(request.GET)
print(request.POST)
print(request.body)
res = JsonResponse({
'books': [
(1, 'c', 10),
(2, 'c++', 11),
(3, 'python', 200),
(4, 'go', 2),
]
})
res.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000'
res.headers['Access-Control-Allow-Headers'] = 'CONTENT-TYPE'
return res
import json
def test_script(request: HttpRequest):
fn = request.GET.get('callback','ttt') # 前端使用哪个函数
text = """{}({})""".format(fn,json.dumps({'a':111100, 'b': 'xxxabcd'})) # 查了数据库
return HttpResponse(text, content_type='application/javascript')
# 主路由
urlpatterns = [
path('admin/', admin.site.urls),
path('emp/', include('employee.urls')), # 2级路由一定要/
path('index', index), # 主页
path('test', test), # 主页
path('testjson', test_json), # application/json请求
path('testscript', test_script), # GET
]
devops\index.html
html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="static/js/jquery-3.6.0.min.js"></script>
</head>
<body>
<!-- <script>
function t234(data) {
console.log(data, '^'.repeat(5));
// 相当于ajax成功时回调
}
</script> -->
<!-- <script src="http://127.0.0.1:8000/testscript?callback=t234"></script> -->
<!-- 相当于下面, 成功时回调 -->
<script>
$(function () {
$.ajax({
type: "GET",
url: "http://127.0.0.1:8000/testscript",
dataType: "jsonp",
success: function(msg) {
console.log(msg,'+'.repeat(12));
}
});
})
</script>
</body>
</html>
ajax的jsonp请求时,不需要添加callback查询参数, 在真正请求时,会自动添加一个随机函数(由ajax内部使用一个函数),如下图:
服务端就响应了随机函数加一堆对象
这里cb函数名, 和jsonp的随机函数名由你调用的文档中决定
diff<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="static/js/jquery-3.6.0.min.js"></script>
</head>
<body>
<!-- <script>
function t234(data) {
console.log(data, '^'.repeat(5));
// 相当于ajax成功时回调
}
</script> -->
<!-- <script src="http://127.0.0.1:8000/testscript?callback=t234"></script> -->
<!-- 相当于下面, 成功时回调 -->
<script>
$(function () {
$.ajax({
type: "GET",
url: "http://127.0.0.1:8000/testscript",
dataType: "jsonp",
+ jsonp: 'cb',
+ jsonpCallback: 'fn',
success: function(msg) {
console.log(msg,'+'.repeat(12));
}
});
})
</script>
</body>
</html>
本文作者:mykernel
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!