概述

对于web应用程序:用户浏览器发送请求.服务器接收并处理请求,然后返回结果,往往返回就是字符串(HTML),浏览器将字符串(HTML),渲染并显示浏览器上·

Ajax和Form表单提交数据的的好处有以下两种:

              Form表单提交数据的时候,呈现在页面上是刷新整个页面·

              Ajax提交数据的时候,只把有用的数据给提交过去,其余的不变·

1:传统的web应用

一个简单操作需要重新加载全局数据

2:AJAX

ajax,Asynchronous JavaScript and XML(异步的JavaScript和XML),一种创建交互式网页应用的网页开发技术方案·

· 异步的JavaScript:

  使用[JavaScript语言]以及相关[浏览器提供类库]的功能向服务端发送请求,当服务端处理请求之后,[自动执行某个JavaSript的回调函数]·

PS:以上请求和响应的整个过程是(偷偷)进行的,页面上无任何感知·

·XML

XML是一种标记语言,是Ajax在和后台交互时传输数据的格式之一·

利用AJAX可以做:

1丶注册时,输入用户名自动检测用户是否已经存在·

2丶登录时,提示用户名密码错误·

3丶删除数据行时,将行ID发送到后台,后台在数据库中删除,数据库删除成功后,在页面DOM中将数据行业删除·

"伪"AJAX

<!DOCTYPE html>
<html> <head lang="en">
<meta charset="UTF-8">
<title></title>
</head> <body> <div>
<p>请输入要加载的地址:<span id="currentTime"></span></p>
<p>
<input id="url" type="text" />
<input type="button" value="刷新" onclick="LoadPage();">
</p>
</div> <div>
<h3>加载页面位置:</h3>
<iframe id="iframePosition" style="width: 100%;height: 500px;"></iframe>
</div> <script type="text/javascript">
//页面加载完成之后自动执行这个函数
window.onload= function(){
var myDate = new Date(); //创建一个时间对象 = 获取当前时间
document.getElementById('currentTime').innerText = myDate.getTime();
          //把它的时间获取到
};
            //LoadPage是由刷新触发的,一点刷新就执行LoadPage函数
function LoadPage(){
var targetUrl = document.getElementById('url').value; //输入什么值就获取都什么值
document.getElementById("iframePosition").src = targetUrl;
            //输入什么URL“iframePosition”标签的src就等于什么
} </script> </body>
</html>

  原生AJAX

ajax主要就是使用[XmlHttpRequest]对象未完成请求的操作,该对象在主浏览器中均存在(除早期的IE),AJAX首次出现IE5.5存在(Active控件)·

1丶XmlHttpRequest对象介绍

xmlHttpRequest对象的主要方法:

1·void open(String metthod, String url, Boolen async)
#用于创建请求
#参数:
method:请求方式(字符串类型),如:POST,GET,DELETE...
url:要请求的地址(字符串类型)
async:是否异步(布尔类型)
2·viod send(String body)
#用于发送请求 #参数
body:要发送的数据(字符串类型)
3·void setRequestHeader(String header,String value)
#用于设置请求同 #参数:
header:请求同的key(字符串类型)
value:请求头的value(字符串的类型) 4· Strig getAllResponseHerders()
#获取所有响应头
#返回值:
响应头数据(字符串类型) 5·String getResponseHeader(String header)
#获取响应头中指定header的值
#参数:
header:响应头的key(字符串类型)
#返回值:
响应头中指定的header对应的值
6· void abort()
#终止请求

  XmlHttpRequest对象的主要属性 :

 (数字类型)
1. Number readyState
状态值(整数) 详细:
0-未初始化,尚未调用open()方法;
1-启动,调用了open()方法,未调用send()方法;
2-发送,已经调用了send()方法,未接收到响应;
3-接收,已经接收到部分响应数据;
4-完成,已经接收到全部响应数据; 2. Function onreadystatechange
当readyState的值改变时自动触发执行其对应的函数(回调函数) 3. String responseText
服务器返回的数据(字符串类型) 4. XmlDocument responseXML
服务器返回的数据(Xml对象) 5. Number states
状态码(整数),如:200、404... 500(服务器错误) 404(没找到) 200系列的(都属正常) 6. String statesText
状态文本(字符串),如:OK、NotFound...

  2丶跨浏览器支持

·XmlHttpRequest

IE7+,Firefox,Chrome,Opera,etc·

·ActiveXObject("Microsoft.XMLHTTP")

IE6,IE5

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body> <h1>XMLHttpRequest - Ajax请求</h1>
<input type="button" onclick="XmlGetRequest();" value="Get发送请求" />
<input type="button" onclick="XmlPostRequest();" value="Post发送请求" /> <script src="/statics/jquery-1.12.4.js"></script>
<script type="text/javascript">
//创建xhr对象
function GetXHR(){
var xhr = null; //默认xhr = null
if(XMLHttpRequest){ //如果(XMLHttpRequest)为真的话表示当前浏览器有这个东西

                          xhr = new XMLHttpRequest();      //通过 new创建一个对象
}else{ //否则的话
xhr = newActiveXobject("Miacosoft.XMLHttp"); //就用ActiveXobject这个插件用xhr去创建
}
return xhr; //这样的话xhr就可以兼容这个浏览器了,兼容浏览器它给的返回值
} //就是一个可以发送那么一个ajax请求的的对象,拿到这个对象我们就可以发请求了 function XhrPostRequest(){
ver xhr = GetXHR(); //获取对象
//定义回调函数
xhr.obnreadystatechange = function(){ //执行成功之后的一个回调,这次请求执行成功了就会自动执行函数,
               //只是定义了,完成之后才会执行,没完成就不会执行这个函数
                   if(xhr.readyState == 4){                  //readyStat == 4 表示已经接收完毕 
//已经接收到全部响应数据,执行以下操作
var data = xhr.responseText; //返回的文本内容
console.log(data); //打印
}
};
//指定连接方式和地址----文件夹
xhr.open("POST","/test/",true); //打开这个链接,以post方式发送URL:/test/
//设置请求头
xhr.setRequestHeade("Content-Type","application/x-www-form-urlencong="utf-8");
//发送请求
xhr.send(); //发送
} }
</script> </body>
</html>

  JQuery Ajax

jQuery其实就是一个Javascript的类库,其将复杂的功能做了上层封装,使得开发者可以在基础上写更少的代码实现更多的功能·

· jQuery不是生产者,而是大自然的搬运工·

· jQuery Ajax本质 XML HttpRequest 或 ActiveXobject

注:2.+版本不再支持IE9以下的浏览器

$.get({
url:"地址",
data:"{"k1":"v1"}", //传输的数据
dataType:"json", // 这样写的话就会在内部执行字符串转成字典
success:function(xx){ //执行成功之后,就会自动执行个xx
obj = JSON.parse(xx) //把字符串转换成字典
} }) $.getjson() //写着一句,相当于dataType在内部设置成json了
$.getscript() //写着一句,相当于dataType在内部设置成script了 $.post({
url:"地址",
data:"{"k1":"v1"}", //传输的数据
success:function(xx){ //执行成功之后,就会自动执行个xx } }) $.ajax({
url:"地址",
type:"post", //表示要发post请求
.....
}) //本质上get和post都会调用ajax方法

  

jQuery.get(...)
所有参数:
url:待载入页面的url地址
data:待发送 key、value参数
success:载入成功时回调函数
dataType:返回内容格式,xml,json,script,text,html jQuery.post(....)
所有参数:
url:带载入页面的url地址
data:待发送 key/value 参数
success:载入成功时回调函数
dataType:返回内容格式,xml,json,script,text,html jQyery.getScript(....)
所有参数:
url;待载入页面的url地址
data:待发送key/value参数
success:载入成功时回调函数 jQuery.ajax(....)
部分参数:
url:请求地址
type:请求方式,GET丶POST(1.9.0之后用method)
headers:请求头
data:要发送的数据
contentType:即将发送信息至服务器的内容编码类型 (默认:"application/x-www-form-urlencoded;charset = utf-8")
async:是否 异步
timeout:设置请求超时时间(毫秒) bempletet:完成之后执行回调函数(全局)
su发送请求前执行回调函数(全局) coccess:成功之后执行的回调函数(全局)
error:失败之后执行的回调函数(全局) accepts:通过请求头发送给服务器,告诉服务器当前客户端可接受的数据类型
dataType:将服务器端返回的数据转换成指定类型
“xml”:将服务器端返回的内容转换成xml格式
“text”:将服务器端返回的内容转换成普通文本格式
“html”:将服务器端返回的内容换换成普通文本格式,在插入DOM中时,如果包含Jvascript标签,则会尝试去执行
“script”:尝试将返回值当做javascript去执行,然后再将服务器端返回的内容转换成普通文本格式
“json”:将服务器端返回的内容转换成相应的Javascript对象
‘jsonp’:JSONP格式
使用 JSONP 形式调用函数时,如"myurl?callback = ?" jQuery 将自动替换 ? 为正确的函数名, 以执行回调函数
如果不指定,jQuery 将自动根据HTTP包MIME信息返回相应类型(an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string converters: 转换器,将服务器端的内容根据指定的dataType转换类型,并传值给success回调函数
$.ajax({
accepts: {
mycustomtype: 'application/x-some-custom-type'
}, // Expect a `mycustomtype` back from server
dataType: 'mycustomtype' // Instructions for how to deserialize a `mycustomtype`
converters: {
'text mycustomtype': function(result) {
// Do Stuff
return newresult;
}
},
});

  

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body> <p>
<input type="button" onclick="XmlSendRequest();" value='Ajax请求' />
</p> <script type="text/javascript" src="jquery-1.12.4.js"></script>
<script> function JqSendRequest(){
$.ajax({
url: "http://c2.com:8000/test/",
type: 'GET',
dataType: 'text',
success: function(data, statusText, xmlHttpRequest){
console.log(data);
}
})
} </script>
</body>
</html>

  跨域AJAX

由于浏览器存在同源策略机制,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档属性·

特别的:由于同源策略是 浏览器的限制,所有请求的发送和响应是可以进行,只不过浏览器不接受罢了·

浏览器同源策略并不是对所有的请求均制约:

·制约:XMLHttpRequese

·不叼:img,iframe,script灯具有src属性的标签

跨域,跨域名访问,如:http://www.c1.com 域名向 http://www.c2.com域名发送请求。

1丶JSONP实现跨域请求 

JSONP(JSONP - JSON with Padding是JSON的一种 “使用模式”),利用 script标签src属性(浏览 器允许script标签跨域)

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body> <p>
<input type="button" onclick="Jsonp1();" value='提交'/>
</p> <p>
<input type="button" onclick="Jsonp2();" value='提交'/>
</p> <script type="text/javascript" src="jquery-1.12.4.js"></script>
<script>
function Jsonp1(){
var tag = document.createElement('script');
tag.src = "http://c2.com:8000/test/";
document.head.appendChild(tag);
document.head.removeChild(tag); } function Jsonp2(){
$.ajax({
url: "http://c2.com:8000/test/",
type: 'GET',
dataType: 'JSONP',
success: function(data, statusText, xmlHttpRequest){
console.log(data);
}
})
} </script>
</body>
</html>

  2丶CORS

随着技术的发展,现在的浏览器可以支持主动设置从而允许跨域请求,既:跨域走远共享(CORS,Cross-Origin Resource Sharing),基本质是设置响应头,使得浏览器允许跨域请求·

*简单请求OR非简单请求

条件:
1丶请求方式:HEAD,GET,POST
2丶请求头信息:
Accept
Accept - Language
Content - Language
Last - Event - ID
Content - Type 对应的值是以下三个中的任意一个
application/x- www - form - urlencoded
multipart/form - data
text/plain
注意:同时满足以上两个条件时,则 是简单请求,否则为复杂请求

*简单请求和非简单请求的区别?

 1·简单请求:一次请求

 2·非简单请求:两次请求,在发送数据之前会会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输·

*关于“预检”*

  请求方式:OPTIONS

  "预检":其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要的发送的消息·

  如何“预检”:

     如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过

     Access-Control-Request-Method

     如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过

     Access-Control-Request-Method

基于cors实现AJAX请求:

  1丶支持跨域,简单请求

服务器设置响应头:Access-Control-Allow-Origin = “域名”或“*”

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body> <p>
<input type="submit" onclick="XmlSendRequest();" />
</p> <p>
<input type="submit" onclick="JqSendRequest();" />
</p> <script type="text/javascript" src="jquery-1.12.4.js"></script>
<script>
function XmlSendRequest(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4) {
var result = xhr.responseText;
console.log(result);
}
};
xhr.open('GET', "http://c2.com:8000/test/", true);
xhr.send();
} function JqSendRequest(){
$.ajax({
url: "http://c2.com:8000/test/",
type: 'GET',
dataType: 'text',
success: function(data, statusText, xmlHttpRequest){
console.log(data);
}
})
} </script>
</body>
</html>

HTML

import tornado.web
import tornado.ioloop class MainHandler(tornado.web.RequestHandler):
def get(self):
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
self.write('{"status": true, "data": "seven"}')

Tornado

  2丶支持跨域,复杂请求

由于复杂请求时,首先会发送“预检”请求,如果‘预检’成功,则发送真实数据·

  ·‘预检’请求时,允许请求方则 需要服务器 设置响应头:Access-Control-Request-Method

  ·‘预检’请求时,允许请求头则需要服务器设置响应头;Access-Control-Request-Headers

  ·‘预检’缓存时间,服务器设置响应头:Access-Control-Max-Age

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body> <p>
<input type="submit" onclick="XmlSendRequest();" />
</p> <p>
<input type="submit" onclick="JqSendRequest();" />
</p> <script type="text/javascript" src="jquery-1.12.4.js"></script>
<script>
function XmlSendRequest(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4) {
var result = xhr.responseText;
console.log(result);
}
};
xhr.open('PUT', "http://c2.com:8000/test/", true);
xhr.setRequestHeader('k1', 'v1');
xhr.send();
} function JqSendRequest(){
$.ajax({
url: "http://c2.com:8000/test/",
type: 'PUT',
dataType: 'text',
headers: {'k1': 'v1'},
success: function(data, statusText, xmlHttpRequest){
console.log(data);
}
})
} </script>
</body>
</html>
import tornado.web
import tornado.ioloop class MainHandler(tornado.web.RequestHandler): def put(self):
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
self.write('{"status": true, "data": "seven"}') def options(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
self.set_header('Access-Control-Allow-Headers', "k1,k2")
self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
self.set_header('Access-Control-Max-Age', 10)

  3丶跨域获取响应头

默认获取到的所有响应头只有基本信息,如果想要获取自定义的响应头,则需要服务器端设置Access-Contorl-Expose-Headers

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body> <p>
<input type="submit" onclick="XmlSendRequest();" />
</p> <p>
<input type="submit" onclick="JqSendRequest();" />
</p> <script type="text/javascript" src="jquery-1.12.4.js"></script>
<script>
function XmlSendRequest(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4) {
var result = xhr.responseText;
console.log(result);
// 获取响应头
console.log(xhr.getAllResponseHeaders());
}
};
xhr.open('PUT', "http://c2.com:8000/test/", true);
xhr.setRequestHeader('k1', 'v1');
xhr.send();
} function JqSendRequest(){
$.ajax({
url: "http://c2.com:8000/test/",
type: 'PUT',
dataType: 'text',
headers: {'k1': 'v1'},
success: function(data, statusText, xmlHttpRequest){
console.log(data);
// 获取响应头
console.log(xmlHttpRequest.getAllResponseHeaders());
}
})
} </script>
</body>
</html>

HTML

class MainHandler(tornado.web.RequestHandler):

    def put(self):
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") self.set_header('xxoo', "seven")
self.set_header('bili', "daobidao") self.set_header('Access-Control-Expose-Headers', "xxoo,bili") self.write('{"status": true, "data": "seven"}') def options(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
self.set_header('Access-Control-Allow-Headers', "k1,k2")
self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
self.set_header('Access-Control-Max-Age', 10)

Tornado

  4·跨域传输cookie

在跨域请求中,默认情况下,HTTP Authentication信息,Cookie头以及用户的SSL证书无论在预检请求中或是在实际请求都是不会被发送·

如果想要发送:

  ·浏览器端:XMLHttpRequest的withCredentials为true

  ·服务器端:Access-Control-Allow-Credentials为true

  ·注意:服务器响应的Access-Control-Allow-Origin 不能是通配符 *

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body> <p>
<input type="submit" onclick="XmlSendRequest();" />
</p> <p>
<input type="submit" onclick="JqSendRequest();" />
</p> <script type="text/javascript" src="jquery-1.12.4.js"></script>
<script>
function XmlSendRequest(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4) {
var result = xhr.responseText;
console.log(result);
}
}; xhr.withCredentials = true; xhr.open('PUT', "http://c2.com:8000/test/", true);
xhr.setRequestHeader('k1', 'v1');
xhr.send();
} function JqSendRequest(){
$.ajax({
url: "http://c2.com:8000/test/",
type: 'PUT',
dataType: 'text',
headers: {'k1': 'v1'},
xhrFields:{withCredentials: true},
success: function(data, statusText, xmlHttpRequest){
console.log(data);
}
})
} </script>
</body>
</html>

HTML

import tornado.web
import tornado.inloop class MainHandler(tornado.web.RequestHandler): def put(self):
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
self.set_header('Access-Control-Allow-Credentials', "true") self.set_header('xxoo', "seven")
self.set_header('bili', "daobidao")
self.set_header('Access-Control-Expose-Headers', "xxoo,bili") self.set_cookie('kkkkk', 'vvvvv'); self.write('{"status": true, "data": "seven"}') def options(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
self.set_header('Access-Control-Allow-Headers', "k1,k2")
self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
self.set_header('Access-Control-Max-Age', 10)

Tornado

  

史上最全的AJAX的更多相关文章

  1. 史上最全的Ajax基础详解

    同步请求和异步请求 先解释一下同步和异步的概念: 同步是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式. 异步是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯 ...

  2. GitHub上史上最全的Android开源项目分类汇总 (转)

    GitHub上史上最全的Android开源项目分类汇总 标签: github android 开源 | 发表时间:2014-11-23 23:00 | 作者:u013149325 分享到: 出处:ht ...

  3. 史上最全面的SignalR系列教程-目录汇总

    1.引言 最遗憾的不是把理想丢在路上,而是理想从未上路. 每一个将想法变成现实的人,都值得称赞和学习. 致正在奔跑的您! 2.SignalR介绍 SignalR实现服务器与客户端的实时通信 ,她是一个 ...

  4. spring + spring mvc + tomcat 面试题(史上最全)

    文章很长,而且持续更新,建议收藏起来,慢慢读! 高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三 ...

  5. Netty 面试题 (史上最全、持续更新)

    文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...

  6. 史上最全Windows版本搭建安装React Native环境配置

    史上最全Windows版本搭建安装React Native环境配置 配置过React Native 环境的都知道,在Windows React Native环境配置有很多坑要跳,为了帮助新手快速无误的 ...

  7. 【Tips】史上最全H1B问题合辑——保持H1B身份终级篇

    [Tips]史上最全H1B问题合辑——保持H1B身份终级篇 2015-04-10留学小助手留学小助手 留学小助手 微信号 liuxue_xiaozhushou 功能介绍 提供最真实全面的留学干货,帮您 ...

  8. 史上最全的java随机数生成算法分享(转)

    这篇文章主要介绍了史上最全的java随机数生成算法,我分享一个最全的随机数的生成算法,最代码的找回密码的随机数就是用的这个方法 String password = RandomUtil.generat ...

  9. 【2016年特别福利】史上最全CSS学习资料大全

    css学习篇 [2016年特别福利]史上最全CSS学习资料大全

随机推荐

  1. DELPHI判断是否64位操作系统

    function IsWin64: Boolean;var  Kernel32Handle: THandle;  IsWow64Process: function(Handle: Windows.TH ...

  2. PHPcms 把盛大登陆换成人人网登陆

    首先要确保你的 phpcms是比较新的版本, v9.3以后的吧 这里说明一个函数 rawurlencode() 本函数将字符串编码成 URL 的字符串专用格式,特殊的字符会转换成百分比符号后面加上二个 ...

  3. js原生继承之——原型式继承实例

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  4. Linux C++程序进行性能分析工具gprof使用入门

    性能分析工具 软件的性能是软件质量的重要考察点,不论是在线服务程序还是离线程序,甚至是终端应用,性能都是用户体验的关键.这里说的性能重大的范畴来讲包括了性能和稳定性两个方面,我们在做软件测试的时候也是 ...

  5. Raphael的transform用法

    Raphael的transform用法 <%@ page language="java" contentType="text/html; charset=UTF-8 ...

  6. jQuery的each函数

    http://www.cnblogs.com/xiaojinhe2/archive/2011/10/12/2208740.html http://www.cnblogs.com/mabelstyle/ ...

  7. Java各种工具下载

    http://yunpan.cn/cyUzqFTu8pEER  提取码 355c  myeclipse2013 http://yunpan.cn/cyUzPi7nC8Z9S  提取码 fc4b  my ...

  8. MyBatis 源码分析——动态代理

    MyBatis框架是如何去执行SQL语句?相信不只是你们,笔者也想要知道是如何进行的.相信有上一章的引导大家都知道SqlSession接口的作用.当然默认情况下还是使用DefaultSqlSessio ...

  9. ubuntu/deepin制作快捷启动图标

    默认情况下系统所有的快捷方式放在/usr/share/applications,打开该目录会看到大量的.desktop文件,每个文件便是一个快捷方式. 有时我们需要自己安装软件,然后添加快捷方式.文件 ...

  10. [转载] ping和telnet的区别

    转载自:http://www.cnblogs.com/Jtianlin/p/4045021.html windown7下打开telnet功能: 控制面板 --- > 程序(小图标下直接到[程序和 ...