返回介绍

使用 Ajax

发布于 2025-04-20 18:52:15 字数 6467 浏览 0 评论 0 收藏

之前看到的例子都是整页地提交,如果提交失败就重新刷新页面,显示错误信息;如果提交正确,就返回完整的新页面或者跳转到其他页面。重新刷新页面和返回新页面意味着整个页面的内容都要重新加载,但事实上其中大部分 HTML 是相同的。这种传统方法浪费了很多带宽,加载得更慢,用户体验不好。另外一个问题是,刷新的页面里应该包含之前未提交成功的数据,不应该让用户重复输入,这也需要大量的逻辑来保证。

大型网站的首页内容都很丰富,比如豆瓣的匿名(未登录状态)首页,除了登录表单,还有顶部导航栏、热点内容和各产品线的推荐内容等。登录时,可不可以在不刷新页面的前提下,只向服务器发送和取回登录必要的数据呢?

Ajax 是 Asynchronous JavaScript and XML 的简称,通过 Ajax 向服务器发送 HTTP 请求,接收服务器返回的 JSON 数据,然后使用 JavaScript 修改网页的局部来实现更新和提交。现在绝大多数 Web 应用都在使用 Ajax。

jQuery 是一个高效、精简并且功能丰富的 JavaScript 工具库,它提供的 API 易于使用且兼容全部主流浏览器,如果不是专业的前端工程师,使用它也可以很方便地操作文档对象、选择文档对象模型(DOM)元素、处理事件、创建动画效果、开发 Ajax 程序等。

首先下载 jQuery:

> wget https://code.jquery.com/jquery-2.2.4.min.js-O static/javascripts/jquery.min.js

jQuery 2.x 与其 1.x 的 API 一样,但是前者只支持 IE 9 及以上的浏览器版本。

登录页面(signin.html)如下:

<!DOCTYPE html>
    <html>
        <head>
            <title>Signin</title>
            <script src="{{url_for('static', filename='javascripts/jquery.min.js')}}"></
                script>
    <style>
        #result{
            margin-top:20px;
            color:red;
          }
      </style>
    </head>
    
<body>
    <div class="container">
        <form action="/signin"method="post"role="form">
            <h2>Please Sign In</h2>
            <input type="name"name="username"placeholder="Username"required
                autofocus>
            <input type="password"name="password"placeholder="Password"required>

            <button class="btn"type="button">SignIn</button>
        </form>

    <div id="result"></div>
    </div>

    <script type='text/javascript'>
        $(function(){
            $('.btn').click(function(){
                  var$result=$('#result');
                  var$username=$('input[name="username"]').val();
                  var$password=$('input[name="password"]').val();
                  $.ajax({
                      url:'/signin',
                      data:$('form').serialize(),
                      type:'POST',
                      dataType:'json'
                  }).done(function(data){
                      if (!data.r){
                          $result.html(data.rs);
                      }else{
                          $result.html(data.error);
                      }
                  });
                });
            });
        </script>
    </body>
</html>

这个页面主要包含如下部分。

1.head:head 标签中可以引用 JavaScript 脚本和样式表(CSS)、提供元信息等。jquery.min.js 这种全局的工具库应该放在最上面,在渲染页面时 jQuery 可以更早加载。除此之外,style 标签还给 id 为 result 的 div 元素添加了样式。

2.form:就是登录表单,其中 action 是提交时请求的地址,method 表示提交方法。表单中有两个 input 标签,分别为用户名和密码,还有一个用来提交的按钮。

3.script:最下面的 script 标签中使用 jQuery 监控类名为 btn 的元素的点击事件。单击“提交”按钮则获取表单中的用户名和密码,通过$.ajax 函数发送 POST 请求。其中 done 是执行成功的回调函数,返回的数据叫作 data,如果 data.r 为 0,表示登录成功,给 id 为 result 的 div 添加 data.rs 中的内容,否则添加 data.error 中的内容。由于 script 会获取页面元素,应该在页面元素的之后出现,所以一般都在 body 的最下面。

上述代码中有一些使用 jQuery 的细节。

  • “$(function(){...})”将会在浏览器加载完页面的基础内容之后立即执行。
  • jQuery 可以使用标签和 CSS 选择器来选取 HTML 元素。举几个例子来看一看:
$("p"):选取<p>元素。
$("p.intro"):选取所有 class="intro"的<p>元素。
$("p#demo"):选取所有 id="demo"的<p>元素。
$('input[name="password"]'):选取所有 name="password"的<input>y 元素。
  • 上例使用了“$result.html”设置内容,html() 可以设置或返回所选元素的内容(包括 HTML 标记)。除此之外,还有 text()(设置或返回所选元素的文本内容)和 val()(设置或返回表单字段的值)。使用 html() 更灵活,因为可以在返回的结果中添加标签和样式。

看一看页面视图:

@app.route('/')
def index():
    return render_template('chapter5/section3/signin.html')


@app.route('/signin', methods=['POST'])
def signin():
    username=request.form['username']
    password=request.form['password']
    error=None
    if len(username)<5:
        error='Password must be at least 5 characters'
    if len(password)<6:
        error='Password must be at least 8 characters'
    elif not any(c.isupper() for c in password):
        error='Your password needs at least 1 capital'
    if error is not None:
        return jsonify({'r':1, 'error':error})
    return jsonify({'r':0, 'rs':'Ok'})

视图分为两个:

  • 首页接受 GET 请求,渲染 signin.html。
  • /signin 页面即上面 Ajax 设置的请求地址,接收用户名和密码,处理之后用 JSON 格式返回结果。需要强调的是,不仅后端需要验证用户名和密码,前端也应该通过 JavaScript 验证用户名和密码的格式是否符合,如果不符合,则直接提示错误而不用产生一次请求,减少后端压力。

使用$.ajax 的时候,提交的数据使用了“$('form').serialize()”,它通过序列化表单值,创建 URL 编码的文本字符串。序列化的值可在生成 Ajax 请求时用在 URL 查询字符串中;否则需要挨个字段拼出来:

data:{'username':$username, 'password':$password}

使用 fetch 实现 Ajax

传统 Ajax 指的是 XMLHttpRequest(XHR),JavaScript 通过它来执行异步请求,jQuery 帮我们把 XMLHttpRequest 封装起来,成为$.ajax、$.get 和$.post 等函数。XHR 在设计上不符合职责分离原则,输入、输出以及状态都放在同一对象中,而且受 XML 影响,其命名也很复杂。

在 ECMAScript 2015(ES6)规范中有一个新的特性:Promise。Promise 对象用于延迟(de-ferred)计算和异步(asynchronous)计算,一个 Promise 对象代表着一个还未完成,但预期将来会完成的操作。Fetch(https://github.com/github/fetch )API 就是基于 Promise 设计的。举个 Ajax 返回 JSON 数据的例子,如果是用原生 XHR 写,会是这样:

var data=new FormData();
data.append('username',$username);
data.append('password',$password);

var xhr=new XMLHttpRequest();
xhr.open('POST', '/signin');

xhr.onreadystatechange=function(){
    if (xhr.readyState==4&&xhr.status==200){
        var data=JSON.parse(xhr.responseText);
        if (!data.r){
            $result.html(data.rs);
        }else{
            $result.html(data.error);
        }
    };
};

xhr.send(data);

如果使用 fetch 则可以写成这样:

fetch('/signin',{
    method:'POST',
    body:data
}).then(function(response){
    return response.json();
}).then(function(data){
    if (!data.r){
        $result.html(data.rs);
    }else{
        $result.html(data.error);
   }
});

从 Firefox 39 以及 Chrome 42 开始,它们已经支持了 Fetch API。为了保证其他浏览器或者低版本的 Firefox 以及 Chrome 也能使用,需要使用 GitHub 开源的 polyfill 脚本:

> wget https://github.com/github/fetch/raw/master/fetch.js-O static/javascripts/fetch.js

在模板中加载这个脚本:

<script src="{{url_for('static', filename='javascripts/fetch.js')}}"></script>

如果再使用 ES 7 提供的 async/awaitAPI,就可以像写同步代码一样写异步代码了:

try{
    let response=await fetch('/signin',{
        method:'POST',
        body:data
    })
    let data=await response.json();
    if (!data.r){
        $result.html(data.rs);
    }else{
        $result.html(data.error);
    }
}catch(e){
    console.log("Oops, error", e);
}

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。