zoukankan      html  css  js  c++  java
  • Ionic-wechat项目边开发边学(三):自定义样式,指令,服务

    摘要

    上一篇文章主要介绍了一个ionic项目的标准目录结构,header标签的使用,以及页面之间的切换。这篇文章实现的功能有: 消息数据的获取, 消息列表的展示, 消息标为已读/未读, 主要涉及的到的知识点有:

    1. ion-list的使用
    2. ion-popup的使用
    3. 通过sass自定义样式
    4. localStorage的使用
    5. 自定义指令和服务

    先看效果图:

    功能分析

    在开始之前, 最好先思考一下消息页面的主要功能, 和大概如何实现. 这样后面写程序才不会乱. 我大体列了一下

    消息的数据暂时用localStorage存储, 但这不是好的方式, localStorage可能会被文件清理掉, 后面会换sqlite存储

    页面布局

    首先在'tab-message.html'中添加聊天消息的布局

    <ion-view>
        <ion-content on-swipe-left="onSwipeLeft()">
            <!--这里的rj-close-back-drop是自定义指令, 后面会讲是干嘛的-->
            <ion-list rj-close-back-drop>
              <ion-item class="item-avatar" on-hold="popupMessageOpthins($index)" rj-hold-active ng-repeat="message in messages">
                  <img ng-src="{{message.pic}}">
                  <!--这个就是来了新消息, 头像上的小红数字-->
                  <span class="rj-sm-red-icon" ng-show="message.showHints"><p ng-bind="message.noReadMessages"></p></span>
                  <h2 ng-bind="message.name"></h2>
                  <p class="rj-list-p" ng-bind="message.lastMessage.content"></p>
                  <span class="rj-push-right" ng-bind="message.lastMessage.time"></span>
              </ion-item>
            </ion-list>
        </ion-content>
    </ion-view>
    

    大家在试这个的时候, 由于'messages'还未定义, 先不绑定, 用实际的值代替,像这样

    <img src="img/ben.png">
    <span class="rj-sm-red-icon"><p>1</p></span>
    <h2>小王</h2>
    <p class="rj-list-p">你在干什么?</p>
    <span class="rj-push-right">12:30</span>
    

    这样就能看到效果了

    自定义样式

    可以看到上图有点丑, 需要我们自己修改样式, 可以自己添加css文件link进来, 但官方推荐使用sass的方式修改, 关于sass的语法, 可以看这个, 看完就差不多可以了.

    首先在项目目录下,运行命令

    $ionic setup sass
    $ionic serve
    

    运行以后, 就会对scss/ionic.app.scss文件监控, 有修改, 会自动编译该文件, 输出到css/ionic.app.css

    所以你每次修改保存scss文件后, 浏览器会看到实时的效果, 非常方便.

    打开scss/ionic.app.scss文件, 如下

    /*
    To customize the look and feel of Ionic, you can override the variables
    in ionic's _variables.scss file.
    
    For example, you might change some of the default colors:
    
    $light:                           #fff !default;
    $stable:                          #f8f8f8 !default;
    $positive:                        #387ef5 !default;
    $calm:                            #11c1f3 !default;
    $balanced:                        #33cd5f !default;
    $energized:                       #ffc900 !default;
    $assertive:                       #ef473a !default;
    $royal:                           #886aea !default;
    $dark:                            #444 !default;
    */
    
    // The path for our ionicons font files, relative to the built CSS in www/css
    $ionicons-font-path: "../lib/ionic/fonts" !default;
    

    可以看到官方预定义的颜色几个颜色, 如果要修改预定义的颜色, 直接修改这里就可以了.

    我们自己的样式, 直接在后面添加. 我们在后面添加

    $item-avatar-border-radius: 0;

    可以发现头像变成方的了, 那怎么知道修改这个变量呢?

    打开www/lib/ionic/scss/目录, 可以看到很多scss文件

    ├── _action-sheet.scss
    ├── _animations.scss
    ├── _backdrop.scss
    ├── _badge.scss
    ├── _bar.scss
    ├── _button-bar.scss
    ├── _button.scss
    ├── _checkbox.scss
    ├── _form.scss
    ├── _grid.scss
    ├── ionicons
    ├── ionic.scss
    ├── _items.scss
    ├── _list.scss
    ├── _loading.scss
    ├── _menu.scss
    ├── _mixins.scss
    ├── _modal.scss
    ...
    

    这些都是官方的样式文件, 找到items.scss文件, 这个就是ion-item相关的样式, 再搜border-radius很快就能找到啦

    具体的细节我就不说啦, 其它的修改都类似, 可以参考我的代码

    popup的使用

    关于$ionicPopup的详细使用, 可以参考官网

    首先在controllers.js文件中添加一个controller:

    .controller('messageCtrl', function($scope, $state, $ionicPopup, localStorageService, messageService) {
        $scope.popup = {
            isPopup: false,
            index: 0
        };
        $scope.onSwipeLeft = function() {
            $state.go("tab.friends");
        };
        $scope.popupMessageOpthins = function($index) {
            $scope.popup.index = $index;
            //这里通过$ionicPopup.show()方法创建了一个自定义的popup
            $scope.popup.optionsPopup = $ionicPopup.show({
                templateUrl: "templates/popup.html",
                scope: $scope,
            });
            $scope.popup.isPopup = true;
        };
        //实现标为已读/未读, 注意$scope.popup.optionsPopup.close()方法
        //用来关闭弹窗, 我竟然找了很久才发现这个接口
        $scope.markMessage = function() {
            var index = $scope.popup.index;
            var message = $scope.messages[index];
            if (message.showHints) {
                message.showHints = false;
                message.noReadMessages = 0;
            }else{
                message.showHints = true;
                message.noReadMessages = 1;
            }
            $scope.popup.optionsPopup.close();
            $scope.popup.isPopup = false;
            messageService.updateMessage(message);
        };
    

    这里要注意两点

    1. 要在routes.js中将该controll传进去
    2. 需要通过自定义样式, 去掉自带的标题和按钮
    //routes.js
    .state('tab.message', {
        url: '/message',
        views: {
            'tab-message': {
                templateUrl: 'templates/tab-message.html',
                controller: "messageCtrl"
            }
        }
    })
    

    自定义指令

    细心的人会发现两个问题:

    1. 弹出popup时, 联系人列表没有动画效果
    2. 弹出popup后, 点击popup以外的地方, popup不能消失, 这两个问题, 就通过自定义指令来解决

    首先在directives.js文件中添加rjCloseBackDrop指令, 用来解决上面第二个问题

    .directive('rjCloseBackDrop', [function() {
            return {
                scope: false,//共享父scope
                restrict: 'A',
                replace: false,
                link: function(scope, iElm, iAttrs, controller) {
                    //要在html上添加点击事件, 试了很久- -!
                    var htmlEl = angular.element(document.querySelector('html'));
                    htmlEl.on("click", function(event) {
                        if (event.target.nodeName === "HTML" &&
                            scope.popup.optionsPopup &&
                            scope.popup.isPopup) {
                            scope.popup.optionsPopup.close();
                            scope.popup.isPopup = false;
                        }
                    });
                }
            };
        }])
    

    再创建rjHoldActive指令, 用来解决第一个问题

    .directive('rjHoldActive', ['$ionicGesture', '$timeout',
            function($ionicGesture, $timeout, $ionicBackdrop) {
                return {
                    scope: false,
                    restrict: 'A',
                    replace: false,
                    link: function(scope, iElm, iAttrs, controller) {
                        $ionicGesture.on("hold", function() {
                            iElm.addClass('active');
                            //300ms后恢复
                            $timeout(function() {
                                iElm.removeClass('active');
                            }, 300);
                        }, iElm);
                    }
                };
            }
        ])
    

    最后分别在ion-listion-item上添加指令

    <ion-list rj-close-back-drop>
        <ion-item class="item-avatar"rj-hold-active ng-repeat="message in messages">
    

    ok, 问题解决, 有点小激动~

    自定义服务

    前面讲的都是界面的东西, 那聊天记录的数据哪里来?
    这里我们自定义一个假json数据, 用来模拟, 在www目录下创建文件data/json/messages.json

    "messages": [{
            "id": 0,
            "name": "李明",
            "pic": "img/adam.jpg",
            "lastMessage": {
                "time": "2015-10-12 15:34:55",
                "content": "你在干什么?",
                "isFromeMe": false
            },
            "noReadMessages": 2,
            "showHints": true
        },...
    

    目前用到的数据都定义在这, 后面还需要什么数据再添加
    我们把数据存到localstorage中, 大家都知道localstorage是基于keyvalue存储的
    总不能把所以人的消息都存在一条key中, 所以我定义两个服务

    1. 把整个json数据拆成单独的message, 把独立的message合并成一个对象
    2. 封装setItem, 基本数据的存储获取

    具体我就不贴代码了, 讲下服务定义好了, 怎么使用, 比如定义了一个test服务:

    .factory('test', ['', function(){
        return{
            dosomething: function(){
                return 0;
            }
        };
    }])
    

    用的时候直接把test注入, test.dosomething()调用:

    .controller('someCtrl', function($scope, test) {
        test.dosomething();
        ...
    }
    

    是不是很简单?

    最后

    这篇写的很长, 其实实现的功能很简单, 主要是要学会如何定义样式, 自定义指令, 自定义服务
    这样在后面实现更复杂的功能时, 不至于纠结这些细节.

    我发现一个人自学, 确实有些困难, 一些小问题百度根本搜不到, google上才比较靠谱

    所以小伙伴们遇到困难, 不妨google一下, 基本都有答案的哦
    有问题欢迎大家评论, 我会的会及时回复~

    Git代码

  • 相关阅读:
    CF833B The Bakery (线段树+DP)
    NOIP 2017 时间复杂度 (模拟)
    NOI 2018 屠龙勇士 (拓展中国剩余定理excrt+拓展欧几里得exgcd)
    中国剩余定理(excrt) 模板
    后缀自动机 模板
    luogu P4248 [AHOI2013]差异
    luogu P3975 [TJOI2015]弦论
    luogu P4770 [NOI2018]你的名字
    luogu P3726 [AH2017/HNOI2017]抛硬币
    luogu P3722 [AH2017/HNOI2017]影魔
  • 原文地址:https://www.cnblogs.com/Frogmarch/p/4993072.html
Copyright © 2011-2022 走看看