• Knockout学习之Single Page Application


    这篇通过一个带导航栏的邮件应用来学习单页应用
    1.添加一个ul标签,通过foreach绑定上数据集合
    2.在ul中添加li标签,因为ul上绑定的数据是数组,所以在li上绑定方式要用
    data-bind="text:$data"
    3.既然是导航,就应该可选择,即点击之后样式要变化,并且有特定时间。
    先通过改变class的方式处理样式变化。class的属性名比较奇怪,居然是css。
    data-bind="css:{selectedClass: (判断语句)}"
    点击时,获取数据并替换绑定的数据,这样与之相关的View就会更新。

    注:table绑定chosenFolderData时用到了with绑定。这与其他语言中的with是一样的意思。
    在这里,它创建了一个绑定上下文,在该table下绑定到chosenFolderData的元素都不需要添加前缀chosenFolderData
    例如mails的绑定。

    4.最后再添加上初始化数据:默认选中某个选项(如Inbox).

    <!DOCTYPE HTML>
    <html>
    <head>
        <title>Single Page Application</title>
        <script src="../JS/jquery-latest.min.js" type="text/javascript"></script>
        <script src="knockout-2.2.0.js" type="text/javascript"></script>
        <script src="mailsData.js" type="text/javascript"></script>
        <style type="text/css">
        body { font-family: Helvetica, Arial }
        input:not([type]), input[type=text], input[type=password], select { background-color: #FFFFCC; border: 1px solid gray; padding: 2px; }
    
    
        .folders { background-color: #bbb; list-style-type: none; padding: 0; margin: 0; border-radius: 7px; 
            background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #d6d6d6), color-stop(0.4, #c0c0c0), color-stop(1,#a4a4a4)); 
            margin: 10px 0 16px 0;
            font-size: 0px;
        }
        .folders li:hover { background-color: #ddd; }    
        .folders li:first-child { border-left: none; border-radius: 7px 0 0 7px; }
        .folders li { font-size: 16px; font-weight: bold; display: inline-block; padding: 0.5em 1.5em; cursor: pointer; color: #444; text-shadow: #f7f7f7 0 1px 1px; border-left: 1px solid #ddd; border-right: 1px solid #888; }
        .folders li { *display: inline !important; } /* IE7 only */
        .folders .selected { background-color: #444 !important; color: white; text-shadow:none; border-right-color: #aaa; border-left: none; box-shadow:inset 1px 2px 6px #070707; }    
    
        .mails { width: 100%; table-layout:fixed; border-spacing: 0; }
        .mails thead { background-color: #bbb; font-weight: bold; color: #444; text-shadow: #f7f7f7 0 1px 1px; }
        .mails tbody tr:hover { cursor: pointer; background-color: #68c !important; color: White; }
        .mails th, .mails td { text-align:left; padding: 0.4em 0.3em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
        .mails th { border-left: 1px solid #ddd; border-right: 1px solid #888; padding: 0.4em 0 0.3em 0.7em; }    
        .mails th:nth-child(1), .mails td:nth-child(1) { width: 20%; }
        .mails th:nth-child(2), .mails td:nth-child(2) { width: 15%; }
        .mails th:nth-child(3), .mails td:nth-child(3) { width: 45%; }
        .mails th:nth-child(4), .mails td:nth-child(4) { width: 15%; }
        .mails th:last-child { border-right: none }
        .mails tr:nth-child(even) { background-color: #EEE; }
          
        .viewMail .mailInfo { background-color: #dae0e8; padding: 1em 1em 0.5em 1.25em; border-radius: 1em; }
        .viewMail .mailInfo h1 { margin-top: 0.2em; font-size: 130%; }
        .viewMail .mailInfo label { color: #777; font-weight: bold; min-width: 2.75em; text-align:right; display: inline-block; }
        .viewMail .message { padding: 0 1.25em; }
        </style>
    </head>
    <body>
        <ul class="folders" data-bind="foreach:folders">
            <!--这里有个特殊的属性css
            注意它不是样式表的意思,而是class的简写
            在这里的意思是,当后面的判断为true时,添加class = selected
            -->
            <li data-bind="text:$data
                ,click:$root.goToFolder
                ,css:{selected:($data == $root.chosenFolderId())}
            "></li>
        </ul>
        
        <table class="mails" data-bind="with:chosenFolderData">
            <thead>
                <tr><th>From</th><th>To</th><th>Subject</th>
                <th>Date</th></tr>
            </thead>
            <tbody data-bind="foreach:mails">
                <tr>
                    <td data-bind="text:from"></td>
                    <td data-bind="text:to"></td>
                    <td data-bind="text:subject"></td>
                    <td data-bind="text:date"></td>
                </tr>
            </tbody>
        </table>
        
        <script type="text/javascript">
            function WebmailViewModel() {
                //Data
                var self = this;
                self.folders = ["Inbox", "Archive", "Sent", "Spam"];
                self.chosenFolderId = ko.observable();
                self.chosenFolderData = ko.observable();
    
                //Behavior
                self.goToFolder = function(folder) {
                    self.chosenFolderId(folder);
                    //这里应该是用Ajax从Server获取数据,为了方便,我们就把直接它放到变量里吧
                    //获得的是普通的JSON格式数据
                    //$.get("http://learn.knockoutjs.com/mail", { folder: folder }, self.chosenFolderData);
                    self.chosenFolderData(mailsData[folder]);
                };
                
                //Show Inbox By Default.
                self.goToFolder("Inbox");
            }
    
            ko.applyBindings(new WebmailViewModel());
        </script>
    </body>
    </html>

     添加查看个人邮件功能

    用户现在可以在各文件夹(导航)间切换。还欠缺个读取邮件的功能。
    好吧,让我们着手定义一个ViewModel属性来把绑定到邮件的数据显示出来。

    在WebmailViewModel里添加

    self.chosenMailData = ko.observable();

    接下来需要更新我们之前绑定的元素,以便用户点击某一个邮件时,ViewModel会加载响应的邮件信息。

    那么,首先在<tr>元素上绑定click
    <tr data-bind="click:$root.goToMail">
    然后在WebmailViewModel中实现goToMail方法。

    self.goToMail = function(mail) {
        self.chosenFolderId(mail.folder);
        self.chosenFolderData(null);
        $.get("/mail", { mailId: mail.id }, self.chosenFolderData);
    };

    最后再把chosenMilData绑定到元素上就能够显示出来了。

    <div class = "viewMail" data-bind="with:chosenMailData">
        <div class="mailInfo>
            <h1 data-bind="text:subject"></h1>
            <p><label>From</label>:<span data-bind="text:from"></span></p>
            <p><label>To</label>:<span data-bind="text:to"></span></p>
            <p><label>Date</label>:<span data-bind="text:Date"></span></p>
        </div>
        <p class="message" data-bind="html:messageContent"></p>
    </div>

    大功告成。现在点击一条邮件的话,页面上就会显示该邮件的详细信息。
    注意一下html绑定的用法。

    <p class="message" data-bind="html:messageContent"></p>

    它相当于是用p.innerHTML = messageContent
    所以要用这个标签绑定数据时,一定要先确定服务器端不会给你发来恶意代码。
    还有Demo的效果如此漂亮是因为页面上有良好的CSS代码(Copy from Knockout official Demo)
    Knockout.js本身不提供UI效果

    <!DOCTYPE HTML>
    <html>
    <head>
        <title>Single Page Application</title>
        <script src="../JS/jquery-latest.min.js" type="text/javascript"></script>
        <script src="knockout-2.2.0.js" type="text/javascript"></script>
        <script src="mailsData.js" type="text/javascript"></script>
        <style type="text/css">
            
    body { font-family: Helvetica, Arial }
    input:not([type]), input[type=text], input[type=password], select { background-color: #FFFFCC; border: 1px solid gray; padding: 2px; }
    body { font-family: Helvetica, Arial}
    .folders { background-color: #bbb; list-style-type: none; padding: 0; margin: 0; border-radius: 7px; 
        background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #d6d6d6), color-stop(0.4, #c0c0c0), color-stop(1,#a4a4a4)); 
        margin: 10px 0 16px 0;
        font-size: 0px;
    }
    .folders li:hover { background-color: #ddd; }    
    .folders li:first-child { border-left: none; border-radius: 7px 0 0 7px; }
    .folders li { font-size: 16px; font-weight: bold; display: inline-block; padding: 0.5em 1.5em; cursor: pointer; color: #444; text-shadow: #f7f7f7 0 1px 1px; border-left: 1px solid #ddd; border-right: 1px solid #888; }
    .folders li { *display: inline !important; } /* IE7 only */
    .folders .selected { background-color: #444 !important; color: white; text-shadow:none; border-right-color: #aaa; border-left: none; box-shadow:inset 1px 2px 6px #070707; }    
    
    .mails { width: 100%; table-layout:fixed; border-spacing: 0; }
    .mails thead { background-color: #bbb; font-weight: bold; color: #444; text-shadow: #f7f7f7 0 1px 1px; }
    .mails tbody tr:hover { cursor: pointer; background-color: #68c !important; color: White; }
    .mails th, .mails td { text-align:left; padding: 0.4em 0.3em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .mails th { border-left: 1px solid #ddd; border-right: 1px solid #888; padding: 0.4em 0 0.3em 0.7em; }    
    .mails th:nth-child(1), .mails td:nth-child(1) { width: 20%; }
    .mails th:nth-child(2), .mails td:nth-child(2) { width: 15%; }
    .mails th:nth-child(3), .mails td:nth-child(3) { width: 45%; }
    .mails th:nth-child(4), .mails td:nth-child(4) { width: 15%; }
    .mails th:last-child { border-right: none }
    .mails tr:nth-child(even) { background-color: #EEE; }
      
    .viewMail .mailInfo { background-color: #dae0e8; padding: 1em 1em 0.5em 1.25em; border-radius: 1em; }
    .viewMail .mailInfo h1 { margin-top: 0.2em; font-size: 130%; }
    .viewMail .mailInfo label { color: #777; font-weight: bold; min-width: 2.75em; text-align:right; display: inline-block; }
    .viewMail .message { padding: 0 1.25em; }
        </style>
    </head>
    <body>
        <!--Folders-->
        <ul class="folders" data-bind="foreach:folders">
            <!--这里有个特殊的属性css
            注意它不是样式表的意思,而是class的简写
            在这里的意思是,当后面的判断为true时,添加class = selected
            -->
            <li data-bind="text:$data
                ,click:$root.goToFolder
                ,css:{selected:($data == $root.chosenFolderId())}
            "></li>
        </ul>
        
        <!--Mails Grid-->
        <table class="mails" data-bind="with:chosenFolderData">
            <thead>
                <tr><th>From</th><th>To</th><th>Subject</th>
                <th>Date</th></tr>
            </thead>
            <tbody data-bind="foreach:mails">
                <tr data-bind="click:$root.goToMail">
                    <td data-bind="text:from"></td>
                    <td data-bind="text:to"></td>
                    <td data-bind="text:subject"></td>
                    <td data-bind="text:date"></td>
                </tr>
            </tbody>
        </table>
        
        <!--Chosen Mail-->
        <div class = "viewMail" data-bind="with:chosenMailData">
            <div class="mailInfo">
                <h1 data-bind="text:subject"></h1>
                <p><label>From:</label><span data-bind="text:from"></span></p>
                <p><label>To:</label><span data-bind="text:to"></span></p>
                <p><label>Date:</label><span data-bind="text:date"></span></p>
            </div>
            <p class="message" data-bind="html:messageContent"></p>
        </div>
    
        <script type="text/javascript">
            function WebmailViewModel() {
                //Data
                var self = this;
                self.folders = ["Inbox", "Archive", "Sent", "Spam"];
                
                //选中的文件夹
                self.chosenFolderId = ko.observable();
                
                //文件夹中的邮件数据
                self.chosenFolderData = ko.observable();
    
                //邮件中的数据(From,To,Subject,Date..)
                self.chosenMailData = ko.observable();
    
                //Behavior
                self.goToFolder = function(folder) {
                    self.chosenFolderId(folder);
    
                    //更换Folder时,清空邮件信息
                    self.chosenMailData(null);
    
                    //这里应该是用Ajax从Server获取数据,为了方便,我们就把直接它放到变量里吧
                    //获得的是普通的JSON格式数据
                    //$.get("http://learn.knockoutjs.com/mail", { folder: folder }, self.chosenFolderData);
                    self.chosenFolderData(mailsData[folder]);
                };
    
                self.goToMail = function(mail) {
                    self.chosenFolderId(mail.folder);
                    
                    //清空文件夹内所有邮件,以在页面上隐藏邮件信息
                    self.chosenFolderData(null);
                    
                    //暂且用全局变量来替代。
                    self.chosenMailData(mailData[Number(mail.id) % 3]);
                    //$.get("http://learn.knockoutjs.com/mail", { mailId: mail.id }, self.chosenFolderData);
                };
                
                //Show Inbox By Default.
                self.goToFolder("Inbox");
            }
    
            ko.applyBindings(new WebmailViewModel());
        </script>
    </body>
    </html>

  • 相关阅读:
    线程安全,syncronized 用法
    线程
    Log4j2
    线性规划
    不要在using语句中调用WCF服务
    kibana 查询语法
    ES中DSL查询相关
    ES通过API调整设置
    ElasticSearch架构思考(转)
    Elasticsearch集群UNASSIGNED
  • 原文地址:https://www.cnblogs.com/TiestoRay/p/2818392.html
Copyright © 2020-2023  润新知