SPA ( 单页应用)很简单

SPA ( 单页应用)很简单

Scroll Down

作为一名后端小伙,每次碰到页面都是感觉蜜汁痛苦的。因为对于前端不是太熟悉,好奇已久的单页应用(SPA)呢,一直没有去实践,只是猜测到怎么做的了,网上的教程也很是敷衍、模糊,所以此次抽空写一下自己前些时间实践时明白的SPA。

SPA 核心 js 源码

以下是一段js源码,是我在做课设的时候根据自己的理解写的。下面将会讲代码:

  • 首先,我们知道单页应用就是将页面碎片化,一般通过 hash 改变触发函数去请求需要的碎片,用来进行动态的组装,同时通过 css 属性,隐藏不需要的部分。
  • 页面定义了一个全局变量 hashSet 数组,用于存储请求的页面碎片的 id 和本身的 hash 组合值。通过符号 ‘@’ 分隔。
  • 每当页面(index)发生了 hashchange事件,则触发下面的函数 hashChangeFun()。
  • 函数通过 window.location.hash.toString()获取当前的 hash 值,并取最后的尾部。
  • 然后遍历全局变量数组 hashSet ,如果 item 不是当前的 hash,则将当前 item 解析出来的 id片段隐藏,如果是当前的 hash,则将其显示出来(通过js操作 css 属性)。
  • 如果遍历完数组 hashSet 仍没有当前 hash 对应的 item,则将当前的 hash 和基本 url 拼装,并通过 ajax 请求,将请求的页面提取的 id 和 hash拼装,并将其加入 hashSet。页面碎片添加到指定的 div中
   /**
     * 核心 SPA 代码
     * @type {*[]}   存储请求的碎片id和hash组合值
     */
    var hashSet=[];
    function hashChageFun()
    {
      let hash=window.location.hash.toString();
      hash=hash.substr(1,hash.length-1);
      let baseUrl="${springMacroRequestContext.contextPath}/view/part/";
      let flag=false;
      for (i=0;i<hashSet.length;i++)
      {
        if (hashSet[i].split("@")[0]===hash)
        {
          $("#"+hashSet[i].split("@")[1]).show();
          flag=true;
        }
        else
        {
          $("#"+hashSet[i].split("@")[1]).hide();
        }
      }
      //排除根hash的情况
      if (!flag&&hash.length!==0)
      {
        console.log("请求Url:"+baseUrl+hash);
        $.get(baseUrl+hash,function (data) {
          $("#father-div").append(data);
          hashSet.push(hash+"@"+data.substr(data.indexOf("id=\"")+4,data.indexOf(" class")-10).trim());
          console.log("id列表:"+JSON.stringify(hashSet));
        });
      }
    }

后端视图控制器

用于响应前端请求基本视图 index 和页面碎片。

@Validated
@Controller
@RequestMapping(value = "/view")
@SuppressWarnings("all")
public class ViewController
{
    /**
     * 登陆页面
     * @return login.ftl
     */
    @Description(description = "登陆视图获取")
    @GetMapping(value = "/user/toLogin")
    public String toLogin()
    {
        return "login";
    }

    /**
     * 登陆成功后进入用户主页
     * SPA 核心页面,基础页面框架
     * @return  index.ftl
     */
    @Description(description = "用户主页视图获取")
    @GetMapping(value = "/user/index")
    public String toIndex()
    {
        return "index";
    }

    /**
     * 用于前端获取详情表格部分
     * 主要是采购界面点击添加的那个药物详情表格
     * 没毛病
     * @return
     */
    @Description(description = "药物采购详情表格获取")
    @GetMapping(value = "/part/details")
    public String details()
    {
        return "part/details";
    }

    /**
     * 获取采购记录基础表格
     * 采购基础表格界面
     * SPA 碎片之一,上面 details 的父碎片
     * @return
     */
    @Description(description = "药物采购基础表格获取")
    @GetMapping(value = "/part/record")
    public String record()
    {
        return "part/record";
    }


    /**
     * 获取数据表格
     * 这个表格计划用来做数据报表的在线显示和查询
     * SPA 大碎片之一
     * @return
     */
    @Description(description = "数据报表父表获取")
    @GetMapping(value = "/part/table")
    public String table()
    {
        return "part/pageTable";
    }


    /**
     * 供SPA 获取库存扣减表格
     * SPA 大碎片之一
     * @return
     */
    @Description(description = "销售扣减表格获取")
    @GetMapping(value = "/part/sellTable")
    public String sellTable()
    {
        return "part/sellTable";
    }


    /**
     * 供SPA用户添加
     * SPA 大碎片之一
     * @return
     */
    @Description(description = "用户添加表格获取")
    @GetMapping(value = "/part/user")
    public String getUserAdd()
    {
        return "part/userAdd";
    }
    /**
     * 供前端获取各个数据表的自己的数据报表表格
     * @param type  根据前端传递的代码进行条件渲染基础表格
     * @param model 传递给模板引擎的参数容器
     * @return
     */
    @Description(description = "数据报表表格生成")
    @GetMapping(value = "/part/dataTable/{type}")
    public String getDataTable(@PathVariable @PositiveOrZero(message = "必须大于等于0") int type, Model model)
    {
       switch (type)
       {
           case 0:
               model.addAttribute("type",0);
               break;
           case 1:
               model.addAttribute("type",1);
               break;
           case 2:
               model.addAttribute("type",2);
               break;
           case 3:
               model.addAttribute("type",3);
               break;
           case 4:
               model.addAttribute("type",4);
               break;
           case 5:
               model.addAttribute("type",5);
               break;
           case 6:
               model.addAttribute("type",6);
       }
       return "part/dataShowTable";
    }



    @GetMapping(value = "/test")
    public String getTestTable()
    {
        return "test/tables";
    }

}

最后

不做演示,因为没有单独去写一个小 demo,源码可以参考药品销售管理系统中的对应部分,主要就是 index.ftl 和 ViewController.java。页面碎片在 templates/part 之下。