在过去一周左右的时间里,我们一直在努力创建一个基于浏览器的GUI /客户端来播放Cardshifter TCG。今天,我刚刚完成了与聊天大厅的非常复杂的布局,还有@SirPython,他们整理了JavaScript / AngularJS代码,在他允许的情况下,我将其包括在内。

这是GitHub上的完整仓库,以防您感兴趣。



我很久没有使用基于表的HTML / CSS布局了,我想知道代码是否如果我有效地使用CSS和Bootstrap等,则结构合理。

这里是lobby.html。请注意,文本{{in brackets}}的各个部分是由Angular注入的。标头和其他内容位于单独的“母体” HTML文件中,该子页面(和其他页面)随游戏流程注入。

 <table id="lobby">
    <tr id="lobby-headers">
        <td id="lobby-title">Cardshifter Lobby</td>
        <td id="lobby-deck-builder" width="20%"><button class="btn btn-navbar csh-button">Deck Builder</button></td>
    </tr>
    <tr id="lobby-invite-request" ng-show="gotInvite">
        <td colspan="2">
            <div id="lobby-accept-invite">
                Game invite from {{invite.name}} to play {{invite.type}}!<br/>
                <input ng-click="acceptInvite(true)" type="button" value="Accept" class="btn btn-success"/>
                <input ng-click="acceptInvite(false)" type="button" value="Decline" class="btn btn-danger"/>
            </div>
        </td>
    </tr>
    <tr id="lobby-list-headers">
        <th id="lobby-message-list-header">Messages</th>
        <th id="lobby-users-list-header">Users Online</th>
    </tr>
    <tr id="lobby-lists" height="400px">
        <td id="lobby-message-list">
            <ul id="lobby-chat-messages">
                <li ng-repeat="message in chatMessages" id="lobby-chat-message">
                    [{{message.timestamp}}] {{message.from}}: {{message.message}}
                </li>
            </ul>
        </td>
        <td id="lobby-users-list">
            <ul id="lobby-users">
                <li ng-repeat="user in users" id="lobby-user">
                    <input ng-model="$parent.$parent.selected_opponent" ng-if="user.userId!=currentUser.id" type="radio"
                           value="{{$parent.user.userId}}" name="user_selection" /> {{user.name}}
                </li>
            </ul>
        </td>
    </tr>
    <tr>
        <td id="lobby-message">
            <textarea ng-model="user_chat_message" ng-keyup="sendMessage($event)"
                id="lobby-chat-text-area" rows="1" cols="75" wrap="off"
                placeholder="Enter chat message..."></textarea>
            <input ng-click="sendMessage()" ng-disabled="sending" type="submit" value="Send" class="btn btn-navbar csh-button"/>
        </td>
        <td id="lobby-invite">
            <input ng-click="startGame()" type="button" value="Invite to game" class="btn btn-warning"/>
        </td>
    </tr>
    <tr id="lobby-mods">
        <td colspan="2" id="lobby-mod-selection">
            <form class="form-inline" role="form">
                <div class="form-group">
                    <label for="mod_selection">Select game type:</label>
                    <div ng-repeat="mod in mods" class="form-control" id="lobby-mod-selector">
                        <input ng-model="$parent.selected_mod" type="radio" value="{{mod}}"
                            name="mod_selection" id="mod_selection"/>
                        {{mod}}
                    </div>
                </div>
            </form>
        </td>
    </tr>


</table>


这是链接到它的lobby.css。请注意,有许多空的选择器类,它们都存在,但目前尚未使用,如果需要,将来可能会使用。

/* WHOLE LOBBY */

#lobby {
    width: 100%;
}

/* TABLE HEADERS */

#lobby-headers {
    font-family: Georgia, Times, "Times New Roman", serif;
    text-align: center;
    color: #DDDDDD;
    background-color: #000000;

}

#lobby-title {
    font-size: 1.5em;
    font-weight: bold;
}

#lobby-deck-builder {}

/* SECTION HEADERS */

#lobby-list-headers {
    font-family: Georgia, Times, "Times New Roman", serif;
    font-size: 1.2em;
}

#lobby-message-list-header {
    text-align: center;
}

#lobby-users-list-header {
    text-align: center;
}

/* MAIN MESSAGE & USERS SECTIONS */

#lobby-lists {
    vertical-align: text-top;
}

#lobby-message-list {
    font-size: 0.8em; !important
}
    /* List of all messages */
    #lobby-chat-messages {
        list-style-type: none;
        padding-left: 0;
    }
        /* Each individual message line */
        #lobby-chat-message {
        }

#lobby-users-list {
    font-size: 0.9em;
    font-family: Georgia, Times, "Times New Roman", serif;
}
    /* List of all users */
    #lobby-users {
        list-style-type: none;
        padding-left: 0;
    }
        /* Each individual user line */
        #lobby-user {
        }

/* FOOTER SECTIONS */

#lobby-message {
    background-color: #000000;
    vertical-align: bottom;
}
    /* TEXT AREA FOR TYPING CHAT MESSAGES*/
    #lobby-chat-text-area {
        outline: none;
        overflow: auto;
        vertical-align: middle;
    }

#lobby-invite {
    background-color: #000000;
    text-align: center;
}

#lobby-mods {}

#lobby-mod-selection {}

    /* DIV CONTAINING RADIO BUTTON AND MOD NAME */
    #lobby-mod-selector {
        border: 1;
    }

/* Game invite accept dialog */
#lobby-invite-request {
    font-family: Georgia, Times, "Times New Roman", serif;
    font-size: 1.6em;
    text-align: center;
    background-color: #0033CC;
    color: #EEEEEE;
    border-top-color: #FFFFFF;
    vertical-align: middle;
}


这里是lobby_controller.js,它是@SirPython编写的AngularJS,将客户端链接到服务器消息:

CardshifterApp.controller("LobbyController", function($scope, $timeout) {
    var CHAT_FEED_LIMIT = 10;
    var ENTER_KEY = 13;
    var MESSAGE_DELAY = 3000;
    var ENTER_KEY = 13;

    $scope.users = [];
    $scope.chatMessages = [];
    $scope.mods = [];
    $scope.currentUser = window.currentUser;
    $scope.invite = {
        id: null,
        name: null,
        type: null
    };
    $scope.gotInvite = false;


    var commandMap = {
        "userstatus": updateUserList,
        "chat": addChatMessage,
        "inviteRequest": displayInvite,
        "availableMods": displayMods,
        "newgame": enterNewGame
    };

    var getUsers = new CardshifterServerAPI.messageTypes.ServerQueryMessage("USERS", "");
    CardshifterServerAPI.sendMessage(getUsers);

    CardshifterServerAPI.setMessageListener(function(message) {
        commandMap[message.command](message);
        $scope.$apply(); // needs to manually updated since this is an event
    }, ["userstatus", "chat", "inviteRequest", "availableMods", "newgame"]);

    $scope.sendMessage = function(e) {
        if(e && e.keyCode !== ENTER_KEY) { // user may hit "enter" key
            return;
        }

        $scope.sending = true;
        var chatMessage = new CardshifterServerAPI.messageTypes.ChatMessage($scope.user_chat_message);
        CardshifterServerAPI.sendMessage(chatMessage);

        $scope.user_chat_message = ""; // clear the input box
        $timeout(function() { // allow another message to be sent in 3 seconds
            $scope.sending = false;
        }, MESSAGE_DELAY);
    }

    $scope.startGame = function() {
        if($scope.selected_mod && $scope.selected_opponent) {
            var startGame = new CardshifterServerAPI.messageTypes.StartGameRequest($scope.selected_opponent,
                                                                                   $scope.selected_mod);
            CardshifterServerAPI.sendMessage(startGame);
        } else {
            // user needs to choose an opponent and/or a mod
            console.log("need to choose mod and/or opponent");
        }
    }

    $scope.acceptInvite = function(accept) {
        var accept = new CardshifterServerAPI.messageTypes.InviteResponse($scope.invite.id, accept);
        CardshifterServerAPI.sendMessage(accept);
        $scope.gotInvite = false;
    }


    // The command map functions:
    /**
    * Based on the content of message, will add or remove
    * a user from the user list.
    */
    function updateUserList(message) {
        if(message.status === "OFFLINE") {
            for(var i = 0, length = $scope.users.length; i < length; i++) {
                if($scope.users[i].userId === message.userId) {
                    $scope.users.splice(i, 1); // remove that user from the array
                    break;
                }
            }
        } else {
            $scope.users.push(message);
        }
    }
    /**
    * Adds a chat message to the message feed. If the message
    * feed is at the maximum limit of messages, deletes the oldest
    * message.
    */
    function addChatMessage(message) {
        if($scope.chatMessages.length === CHAT_FEED_LIMIT) {
            // remove the oldest chat message
            $scope.chatMessages.shift();
        }

        var now = new Date();
        var YMD = now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate();
        var HMS = now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds();
        message.timestamp = YMD + " " + HMS;

        $scope.chatMessages.push(message);
    }
    /**
    * Shows buttons and a message to this client for accepting
    * or declining a game request.
    */
    function displayInvite(message) {
        $scope.invite.id = message.id;
        $scope.invite.name = message.name;
        $scope.invite.type = message.gameType;
        $scope.gotInvite = true;
    }
    /**
    * Shows to the user a list of all available mods.
    */
    function displayMods(message) {
        $scope.mods = message.mods;
    }
    /**
    * Stores the game ID in currentUser for other controllers
    * to use and navigates to the deck-builder page for the
    * user to select a deck.
    */
    function enterNewGame(message) {
        currentUser.currentGameId = message.gameId;
        console.log("change to game");
    }
});


评论

您在ng-repeat上有id =“ lobby-user”。这是无效的;同一ID的HTML元素不能超过一个。使用课程!

#1 楼

背景:我在一家公司担任Web开发人员。我是这里唯一的Angular员工,我们在未开发的CRM项目中使用Angular,所以我的答案将主要针对Angular(因为这里没有其他人)。


id属性

首先是第一件事-您正在使用大量id属性。一般来说,仅当id是HTML中的唯一“对象”时,才要使用js-*。毕竟,ID是不能重复的。
用例要求它重复。

您不应将ID用于样式挂钩。我个人避免完全使用它们,除非我想使用同一页面的锚点-我更喜欢使用以height开头的类,或者,当我想要访问Angular时,我更喜欢使用指令来访问Angular(像你一样) 。

内联样式。

内联样式是不好的做法-您确实想尽可能地分离表示和内容,这包括尽可能将CSS与HTML分离。使用CSS规则应用任何样式。您可以使用任何喜欢的方法-我更喜欢CSS的BEM模型,但是Bootstrap模型也很好,或者语义HTML也可以。

这也适用于样式属性-例如,width$scope都是样式属性。这些应该在CSS文件中。

$scope

请尽可能不要使用controllerAs。在Angular 2.0中已将其删除,使您的代码难以推理。而是使用$scope语法。这在引擎盖下使用lobby.user,但可确保您不会陷入任何讨厌的原型坑洞中,当使用隔离范围时,Angular会挡住自己的路。这也使您的模板更易于推理,因为您可以清楚地关联事物-userdata-ng-*更有意义。

HTML验证

我不发誓使用data-*属性。使用伪指令时,实际上是在创建自定义元素,根据规范,这些元素具有未以data-ng-*为前缀的属性。另外,浏览器会忽略未知属性-注意不要使属性名称与规范中的名称相同,我认为还可以。如果要为所有内容加上data-前缀,请在构建步骤中进行; angular将自动删除所有window前缀。


window访问权限

永远不要访问window,尤其是不能从控制器内部访问。 $window是DOM访问,这是错误的;使用$window。 DOM访问应仅限于指令。您可以在控制器中使用$window,尽管几乎可以肯定要在指令中使用它。

window是Angular自己的window版本,包装在其依赖项注入容器中-这使您可以嘲笑它,如果你想。您不能使用CHAT_FEED_LIMIT做任何事情。

关注点分离

您的Angular代码并不是完全分开的。您的控制器正在做很多事情。例如,您有很多常量-window-实际上应该是角常量。正如我在下面提到的,控制器应仅将UI和任何用户状态与应用程序的其余部分粘合在一起;与服务器端的MVC模型类似,它们应该非常笨拙且不起作用。

您希望尽可能地拆分代码,以便每件事只承担一个责任。 />
CardshifterAPI

这似乎像window上的命名空间。您不应该依赖Angular在new CardshifterServerApi.messageTypes.ServerQueryMessage("USERS", "")中的东西。您有一个致命的依赖项注入容器,您绝对应该使用它。另外,ServerQueryMessage很奇怪。我不知道这是怎么做的(我已经简短地查看了您的消息来源,但不确定),但是(对我而言)它看起来很奇怪,这与我编写的依赖项注入说明有关;您可以非常容易地使用Angular将其作为new ServerQueryMessage()注入,然后改为window。这样看起来好很多,并且在这种情况下消除了对!important依赖性的需求。

您的CardshifterAPI本身似乎承担了太多责任。我意识到这是一个独立的脚本,在其余的Angular代码之前已加载。依靠代码顺序是维护的噩梦-我建议您使用webpack或browserify和/或尝试将CardshifterAPI文件转换为Angular模块。

布局表

否。将表格用于表格数据。

!important

否。不要使用!important!important几乎总是表示不了解CSS的级联行为。唯一一次要使用strict mode的情况是,当您需要覆盖第3方代码中某些您不能覆盖usign特殊性的内容时。

$parent

打开它,对其进行学习, 爱它。它免费为您提供了许多好处,并迫使您编写符合标准的javascript代码。

$parent

再次访问$parent时,通常表明您正在执行此操作错误的(t​​m)。与隔离范围一起使用指令。如果使用selected-mod,则将调用站点直接耦合到作用域的层次结构,这使您的代码不可重用。代替

<div ng-repeat="mod in mods" class="form-control" id="lobby-mod-selector">
    <input ng-model="$parent.selected_mod" type="radio" value="{{mod}}"
        name="mod_selection" id="mod_selection"/>
    {{mod}}
</div>


创建以$scope作为参数的指令,然后使用双向绑定将其分配给作用域。这是一个示例:

module.directive('modList', function() {
  return {
    scope: {
      model: '='
    },
    controller: function($scope, mods) {
      $scope.mods = mods;
    },
    template: '<div ng-repeat="mod in mods"><mod moderator="mod" model="model"></mod></div>'
  };
})
.directive('mod', function() {
  return {
    scope: { 
      moderator: '=',
      model: '='
    },
    template: '<input type="radio" ng-value="moderator" name="mod_selection" ng-model="model"> {{ moderator }}'
  }});


然后这样称呼它:

<mod-list model='selected_mod'></mod-list>


显然,可以改进,但是看起来更具语义。注意:您不能动态生成名称,因此将无法使用带有name属性的表达式。从本质上讲,这意味着您将无法将该指令重用于其他任何用途(没有动态单选列表)。

在一般的控制器上,

认为没有理由再没有独立控制器了。正如您在上面的示例中可能已经注意到的那样,我直接在行中分隔了控制器。这是因为在Angular 2.0中,控制器将消失(ng-controller也是如此)。控制器几乎总是只与路由,指令或acceptInvite结合使用,并且实际上并不需要在隔离的环境中对其进行测试,因为它们仅应用于将UI代码粘合到服务代码。结果,我也觉得您当前的控制器本质上是一个神类,您应该将大量代码重构为服务。例如,value='{{mod}}'知道如何同时构造消息它需要并发送它。相反,这应该调用可以完成所有繁重工作的服务;唯一应该在控制器中的是UI状态(再次,我认为)。例如,而不是

$scope.acceptInvite = function(accept) {
  var accept = new CardshifterServerAPI.messageTypes.InviteResponse($scope.invite.id, accept);
  CardshifterServerAPI.sendMessage(accept);
  $scope.gotInvite = false;
}


我更喜欢这个

$scope.acceptInvite = function(acceptOrDecline) {
  // inviteService is a bit contrived, you'd probably want this in some other service
  // but it is an example
  $scope.inviteService.respondToInvite($scope.invite.id, acceptOrDecline).then(function() {
    $scope.gotInvite = false;
  });
}


ng-value

这不会像您期望的那样起作用;请改用value。在施加角载荷之前,{{mod}}的值为ng-value{{}}确保不加载Angular时不设置此值。同样,这使您可以使用不必指定value="{{mod}}"的表达式。例如,ng-value="mod"变为q4312079q。


这就是我现在能想到的。主要优点是使用指令,删除内联样式。我还有很多事情要做,但是我的时间有限:-)也许我会贡献力量。

评论


\ $ \ begingroup \ $
我不得不完全不同意您关于CardshifterServerAPI的建议。我之所以说“愚蠢”是因为我的知识是AngularJS很差。这行新的CardshifterServerApi.messageTypes.ServerQueryMessage(“ USERS”,“”)将创建严格在Cardshifter服务器代码本身中定义的新ServerQueryMessage。这样可以正确格式化消息,因此代码不必进行硬编码和重复任何JSON代码。并且创建整个服务以仅发送许多其他类型中的一种类型的消息?似乎没有必要。请在聊天室中回复此消息。
\ $ \ endgroup \ $
– SirPython
2015年8月11日,下午1:37

\ $ \ begingroup \ $
不,您是对的,您不想为每条消息创建一项服务。但是,您确实想为每个逻辑消息分组创建一个服务。例如,您可能有一个针对用户,卡片等的服务。您可能希望此服务知道如何创建消息,而不是消息的实现。这非常适合工厂模式。
\ $ \ endgroup \ $
–丹
15年8月11日在7:48

\ $ \ begingroup \ $
考虑到$ scope不是2.0版,是否还可以使用$ scope,考虑到2.0将(至少)具有围绕ES6构建的一些功能,可能不会使用一段时间了吗?而且,可以改用它,还是使用controllerA更好?
\ $ \ endgroup \ $
– SirPython
2015年8月19日在20:42



\ $ \ begingroup \ $
使用$ scope没什么错,但是最终您必须确保始终将对象放在范围内的对象上,因此不妨使用controlleras。如果不在范围内使用对象,则会遇到原型继承和隔离范围的问题。 IMO对此进行了修复
\ $ \ endgroup \ $
–丹
2015年8月19日在20:45



#2 楼

好吧,有很多代码需要审查。我已尽力将其分为每种语言。我避免回顾Angular,因为它是我不满意的库。

HTML:




ng-*属性。

无效的HTML。您必须使用data-ng-*

根据文档,data-ng-*是有效的,将被检测到。


仍使用<td width="foo"><td height="foo">吗?我们是在90年代吗?

从HTML 4.01开始不赞成使用这些属性,请改用CSS。

400px也是无效值。您必须指定不带px的值(是的,它仅支持像素和百分比)。

,请使用CSS。


您到处都有稀疏字段!

甚至没有一个<form>

哦,等等!有这个:<form class="form-inline" role="form">,但是它甚至没有提交按钮或其他任何东西。


有些id需要重新措词。

一个例子是id="lobby-chat-text-area"。我知道这是一个textarea!这是为了什么敬酒?没有!这是一条消息!对于此示例,更改为id="lobby-chat-message"会更好。



CSS:




您的样式是空的!

例如:#lobby-deck-builder {}
如果它们为空,则表示它们什么也没做。如果他们什么都没做,则可以将其删除。


您有古怪的凹痕。

看看这个烂摊子:

#lobby-message-list {
    font-size: 0.8em; !important
}
    /* List of all messages */
    #lobby-chat-messages {
        list-style-type: none;
        padding-left: 0;
    }
        /* Each individual message line */
        #lobby-chat-message {
        }


虽然它使您更轻松,但会使其他人变得复杂。请不要这样做!


重复的样式。

我确定您知道DRY的含义。

您有以下几行:

#lobby-message-list-header {
    text-align: center;
}

#lobby-users-list-header {
    text-align: center;
}


什么时候,您可以这样写:

#lobby-users-list-header, #lobby-message-list-header {
    text-align: center;
}


或移动它们上课font-family也是如此。



JavaScript:

关于您的JavaScript没什么可说的。


您重复了两次var ENTER_KEY = 13;

您正在滥用对象。

您具有以下内容:

var commandMap = {
    "userstatus": updateUserList,
    "chat": addChatMessage,
    "inviteRequest": displayInvite,
    "availableMods": displayMods,
    "newgame": enterNewGame
};


为什么不穿您不只是在这里分配功能吗?对象也有好处!


您丢失了函数updateUserList

您留下了break;。那里的中断退出了for循环。您只需使用return;即可。



评论


\ $ \ begingroup \ $
如果他重复var ENTER_KEY = 13;而且没有注意到,他没有使用严格模式。那将是我对JS的第一个建议。
\ $ \ endgroup \ $
– ANeves认为SE是邪恶的
2015年8月9日在13:49

\ $ \ begingroup \ $
关于CSS的“古怪的缩进”:这不是CSS的缩进样式。实际上,它是Sass(嵌套)提供的4个输出设置之一。
\ $ \ endgroup \ $
–cimmanon
2015年8月9日在16:52



\ $ \ begingroup \ $
我个人看不到空CSS类的危害。它们是方便的占位符,提醒您定义了哪些类,但未指定其样式。
\ $ \ endgroup \ $
–RubberDuck
2015年8月9日在17:50

\ $ \ begingroup \ $
@RubberDuck它们不会立即造成伤害,但是会造成性能下降。另外,您可以轻松地用/ * TODO之类的注释替换它们:在#lobby-deck-builder * /上添加背景,您将被设置。
\ $ \ endgroup \ $
–伊斯梅尔·米格尔(Ismael Miguel)
15年8月9日在18:44

\ $ \ begingroup \ $
我个人认为空班级对表演的影响可以忽略不计...
\ $ \ endgroup \ $
–丹
15年8月10日在9:49

#3 楼

用于布局的表

这是对表元素的明显和明显的误用。表格用于表示表格数据,仅此而已。电子表格中的相同内容有意义吗?如果答案是否定的(如本例所示),则不要使用表格。请改用CSS控制布局。

ID过多

您的CSS中没有单个非ID选择器。那是一些严重的代码异味。通过这样做,您实际上是在暗示文档中的每个元素与其他元素绝对没有任何共同之处。真?在任何地方都没有合适的元素选择器(psst,如果您使用的是语义上合适的标记而不是表和div,那么实际上您将拥有可以用作样式挂钩的其他元素)?还是一堂课?还是后代选择器?


!important当您不需要

时,您只在整个样式表中使用id,并且所有对象都具有相同的特异性。在极少数情况下,!important是合适的,而这不是其中之一。

#lobby-message-list {
    font-size: 0.8em; !important
}


无效的CSS

您必须具有边框的单位(边框宽度),除非值是0。

#lobby-mod-selector {
    border: 1;
}


学习爱速记

#lobby-invite-request {
    font-family: Georgia, Times, "Times New Roman", serif;
    font-size: 1.6em;
}


/>成为

#lobby-invite-request {
    font: 1.6em Georgia, Times, "Times New Roman", serif;
}


除非需要保留以前声明的值,否则将通过使用速记来获得更紧凑的CSS。

#lobby-chat-messages {
    list-style-type: none;
}


成为

#lobby-chat-messages {
    list-style: none;
}


评论


\ $ \ begingroup \ $
“这显然是对表元素的明显滥用。”严厉而诚实的一句话,我真诚地希望您能看到这个问题并指出类似的事情!您认为使用div代替表元素是否有意义?
\ $ \ endgroup \ $
– ran
2015年8月9日在17:28

\ $ \ begingroup \ $
好吧,div没有任何语义含义。您可以使用它,这很好,但是几乎可以肯定,使用新的HTML5分段元素(section,aside,header,footer等)会更好。
\ $ \ endgroup \ $
–cimmanon
15年8月9日,17:31

\ $ \ begingroup \ $
嗯,从来没有听说过这些。浏览器之间是否存在兼容性问题?您知道适合他们的良好文档的链接吗?
\ $ \ endgroup \ $
– ran
2015年8月9日在17:33

\ $ \ begingroup \ $
实际上,较旧的浏览器会将其视为跨度,而不是div(div实际上默认情况下对其应用了样式:display:block)。唯一有问题的浏览器是IE8和更低版本(请参阅:en.wikipedia.org/wiki/HTML5_Shiv)。其他所有浏览器都可以让您以与其他元素相同的样式来设置未知元素的样式。对于HTML5元素信息,我喜欢HTML5 Doctor。
\ $ \ endgroup \ $
–cimmanon
15年8月9日在18:10

\ $ \ begingroup \ $
Angular(第1.3版-您正在使用Angular 1.3+,对吗?)不支持IE8或更早版本,因此这一点尚无定论。对于HTML5医生+1,我在他们的办公桌上打印了流程图。
\ $ \ endgroup \ $
–丹
2015年8月10日9:37



#4 楼

除了@IsmaelMiguel所做的事情之外,没有什么要掩盖的了:


世俗的事物:


事物,作为样式事物,但是:


font-family: Georgia, Times, "Times New Roman", serif;
font-size: 1.6em;
text-align: center;
background-color: #0033CC;
color: #EEEEEE;
border-top-color: #FFFFFF;
vertical-align: middle;



我发现更好地按字母顺序或按字母顺序堆叠事物(例如:aligncolor s,font s,text),也可以按行长堆叠它们。这一点也适用于JS。


更多有关常规样式的信息:

// user needs to choose an opponent and/or a mod
console.log("need to choose mod and/or opponent");


最好保留列表的顺序相同,而不是交换它们。另外,.log的文字非常清晰,注释有些多余。



    </tr>


</table>



这里您有多余的一行,如果这是您的风格,那也没关系,但是,请在整个代码中将其保持不变。


不确定这是怎么回事:

但是,如果是错误,则可能要看看它。


console.log("change to game");


毫无意义,值得大写和句点。


其他所有内容:



var YMD = now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate();
var HMS = now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds();



与那样的串联相比,我发现最好这样做join代替。

var YMD = [now.getFullYear(), now.getMonth() + 1, now.getDate()].join("-");
var HMS = [now.getHours(), now.getMinutes(), now.getSeconds()].join(":");


您甚至可以使用最终组合:

message.timestamp = [YMD, HMS].join(" ");


它也是一个如果您想扩展或不进行扩展,稍后再轻松一点。



CardshifterServerAPI.setMessageListener(function(message) {
// ...
}, ["userstatus", "chat", "inviteRequest", "availableMods", "newgame"]);



您应该避免手动更新该文件,而是通过从对象获取键。这样的事情会起作用:

var keys = [];
for(var k in commandMap){ keys.push(k); }
CardshifterServerAPI.setMessageListener(function(message) {
// ...
}, keys);



像Chat.SE一样,可以使用声音和高亮显示的名称来实现@ ping系统。并且与Chat.SE相似,为服务器聊天提供类似于Chat.SE上的mod的特殊颜色会很好,否则,我的麻烦制造者可能会倾向于使用“服务器聊天2”作为用户名进行注册,并混淆所有人。 br />

评论


\ $ \ begingroup \ $
两次都很好地捕获了“ Phrancis”名称,看起来我已经用相同的用户名连接了两个实例,这是我们将在短期内实现的。 :)
\ $ \ endgroup \ $
– ran
15年8月9日在7:27

\ $ \ begingroup \ $
感谢您最后添加的建议!关于console.logs:这些是临时的。该应用程序的其他部分仍在处理中,而这些是最不重要的部分。因此,这些被用作提醒(以及测试中的“断点”)。
\ $ \ endgroup \ $
– SirPython
2015年8月9日14:16

\ $ \ begingroup \ $
通过您推荐的任何方法重新排序CSS属性都没有任何好处。结束tr / table标记之间的多余空格很容易归因于模板引擎中的怪癖,因此很少值得考虑。
\ $ \ endgroup \ $
–cimmanon
2015年8月9日在16:56

#5 楼

您应该在JS脚本中使用严格模式。它将避免许多常见错误。

请参阅我链接的MDN文章中的“严格模式中的更改”部分。
使用严格模式的一些优点:


不允许全局变量(当开发人员“忘记”声明它们时);
不允许重复变量(例如两次声明ENTER_KEY);
函数参数必须唯一( function foo (x, x) { })。


评论


\ $ \ begingroup \ $
我想你的答案需要更多的帮助。更好地解释它的作用,如何做以及如何防止错误将是有用的。
\ $ \ endgroup \ $
–伊斯梅尔·米格尔(Ismael Miguel)
15年8月10日在9:46

\ $ \ begingroup \ $
@IsmaelMiguel我同意它需要更多的肉。我改进了它,但也使它成为CW以吸引其他人做出贡献。
\ $ \ endgroup \ $
– ANeves认为SE是邪恶的
15年8月10日在10:19

\ $ \ begingroup \ $
好多了。您可能需要等待3分钟才能进入社区Wiki,所以我可以给您+10
\ $ \ endgroup \ $
–伊斯梅尔·米格尔(Ismael Miguel)
15年8月10日在10:21

\ $ \ begingroup \ $
很好,我不会因此而贫穷。 :p
\ $ \ endgroup \ $
– ANeves认为SE是邪恶的
15年8月10日在10:24