Angular-UI手風琴效果源碼分析

/*
 * angular-ui-bootstrap
 * http://angular-ui.github.io/bootstrap/

 * Version: 0.14.3 - 2015-10-23
 * License: MIT
 */
angular.module("ui.bootstrap", ["ui.bootstrap.tpls","ui.bootstrap.accordion","ui.bootstrap.collapse"]);
angular.module("ui.bootstrap.tpls", ["template/accordion/accordion-group.html","template/accordion/accordion.html"]);
angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])

.constant('uibAccordionConfig', {//constant 可以將一個已經(jīng)存在的變量值注冊為服務
  closeOthers: true
})

.controller('UibAccordionController', ['$scope', '$attrs', 'uibAccordionConfig', function($scope, $attrs, accordionConfig) {
  // This array keeps track of the accordion groups
  this.groups = [];//用數(shù)組來保存所有的手風琴組

  // Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to //確保所有的手風琴組是關閉的攒砖,除非其它關閉的并不是
  this.closeOthers = function(openGroup) { //關閉函數(shù) 如果oneAtATime存在且為true
    var closeOthers = angular.isDefined($attrs.closeOthers) ?  $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;//判斷$attrs.closeOthers是否定義過
    if (closeOthers) {
      angular.forEach(this.groups, function(group) { //遍歷所有的手風琴組
        if (group !== openGroup) { //如果沒有規(guī)定打開的手風琴組吴裤,就全部關閉
          group.isOpen = false;
        }
      });
    }
  };

  // This is called from the accordion-group directive to add itself to the accordion //要向手風琴組添加對象時調(diào)用的函數(shù)
  this.addGroup = function(groupScope) { //添加的是作用域
    var that = this;
    this.groups.push(groupScope);

    groupScope.$on('$destroy', function(event) {//當監(jiān)聽到銷毀旧找,就移除手風琴組
      that.removeGroup(groupScope);
    });
  };

  // This is called from the accordion-group directive when to remove itself //要移除手風琴組時候調(diào)用,需要移除數(shù)組中對應的項
  this.removeGroup = function(group) { 
    var index = this.groups.indexOf(group);
    if (index !== -1) {
      this.groups.splice(index, 1);
    }
  };

}])

    // The accordion directive simply sets up the directive controller 這個指令只是建立了這個指令的控制器和添加了一個css類型
    // and adds an accordion CSS class to itself element.
    //<uib-accordion close-others="oneAtATime">  </uib-accordion> 對應指令 模板<div class=\"panel-group\" ng-transclude></div>
.directive('uibAccordion', function() {
  return {
    controller: 'UibAccordionController',
    controllerAs: 'accordion',//控制器別名
    transclude: true,//可以替換
    templateUrl: function(element, attrs) { //
      return attrs.templateUrl || 'template/accordion/accordion.html';
    }
  };
})

    // The accordion-group directive indicates a block of html that will expand and collapse in an   這個指令表示出一段html展開或者折疊在一個手風琴效果中
    // <uib-accordion-group heading="Static Header, initially expanded" is-open="status.isFirstOpen" is-disabled="status.isFirstDisabled">This content is straight in the template. </uib-accordion-group>  的指令
.directive('uibAccordionGroup', function() {
  return {
    require: '^uibAccordion',         // We need this directive to be inside an accordion //我們需要這個指令來在其中放入一個手風琴效果
    transclude: true,              // It transcludes the contents of the directive into the template 允許這個指令的內(nèi)容到模板中進行替換
    replace: true,                // The element containing the directive will be replaced with the template
    templateUrl: function(element, attrs) { //調(diào)用模板
      return attrs.templateUrl || 'template/accordion/accordion-group.html';
    },
    scope: {
      heading: '@',               // Interpolate the heading attribute onto this scope //傳遞的是字符串
      isOpen: '=?', //=雙向綁定
      isDisabled: '=?' //?告訴指令如果沒有找到依賴的指令麦牺,不要拋出異常钮蛛。
    },
    controller: function() { //設置當前對象的heading 
      this.setHeading = function(element) {
        this.heading = element;
      };
    },
    link: function(scope, element, attrs, accordionCtrl) {
      accordionCtrl.addGroup(scope);//把當前scope添加進 手風琴數(shù)組

      scope.openClass = attrs.openClass || 'panel-open';//展開的樣式
      scope.panelClass = attrs.panelClass;//獲取具體定義的類名
      scope.$watch('isOpen', function(value) {//監(jiān)聽isOpen,判斷是否發(fā)生變化 
        element.toggleClass(scope.openClass, !!value);//如果isOpen為ture時剖膳,就添加展開的樣式
        if (value) {
          accordionCtrl.closeOthers(scope);
        }
      });

      scope.toggleOpen = function($event) { //手風琴開關函數(shù)
        if (!scope.isDisabled) { //scope.isDisabled為false時執(zhí)行
          if (!$event || $event.which === 32) {
            scope.isOpen = !scope.isOpen;
          }
        }
      };
    }
  };
})

// Use accordion-heading below an accordion-group to provide a heading containing HTML
    //使用手風琴標題下面的手風琴組魏颓,提供一個內(nèi)容標簽
    //對應指令 <uib-accordion-heading> I can have markup, too! <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': status.open, 'glyphicon-chevron-right': !status.open}"></i> </uib-accordion-heading>
.directive('uibAccordionHeading', function() {
  return {
    transclude: true,   // Grab the contents to be used as the heading
    template: '',       // In effect remove this element!
    replace: true,
    require: '^uibAccordionGroup',
    link: function(scope, element, attrs, accordionGroupCtrl, transclude) {
      // Pass the heading to the accordion-group controller
      // so that it can be transcluded into the right place in the template
      // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
      accordionGroupCtrl.setHeading(transclude(scope, angular.noop));
    }
  };
})

    // Use in the accordion-group template to indicate where you want the heading to be transcluded 
    // You must provide the property on the accordion-group controller that will hold the transcluded element
    //<a href tabindex="0" class="accordion-toggle" ng-click="toggleOpen()" uib-accordion-transclude="heading"><span ng-class="{'text-muted': isDisabled}">{{heading}}</span></a>
.directive('uibAccordionTransclude', function() {
  return {
    require: ['?^uibAccordionGroup', '?^accordionGroup'],
    link: function(scope, element, attrs, controller) { 
      controller = controller[0] ? controller[0] : controller[1]; // Delete after we remove deprecation
      scope.$watch(function() { return controller[attrs.uibAccordionTransclude]; }, function(heading) {//{{heading}}  
        if (heading) {
          element.find('span').html('');
          element.find('span').append(heading);
        }
      });
    }
  };
});

/* Deprecated accordion below 
//棄用的手風琴 dead code
angular.module('ui.bootstrap.accordion')

  .value('$accordionSuppressWarning', false)
    //
  .controller('AccordionController', ['$scope', '$attrs', '$controller', '$log', '$accordionSuppressWarning', function($scope, $attrs, $controller, $log, $accordionSuppressWarning) {
    if (!$accordionSuppressWarning) {
      $log.warn('AccordionController is now deprecated. Use UibAccordionController instead.');
    }

    angular.extend(this, $controller('UibAccordionController', { //擴展當前控制器
      $scope: $scope,
      $attrs: $attrs
    })); //加載控制器并傳入一個作用域,同AngularJS在運行時做的一樣
  }])

  .directive('accordion', ['$log', '$accordionSuppressWarning', function($log, $accordionSuppressWarning) {
    return {
      restrict: 'EA',
      controller: 'AccordionController',
      controllerAs: 'accordion', //控制器別名
      transclude: true,
      replace: false,
      templateUrl: function(element, attrs) {
        return attrs.templateUrl || 'template/accordion/accordion.html';//替換成 <div class=\"panel-group\" ng-transclude></div>
      },
      link: function() {
        if (!$accordionSuppressWarning) {
          $log.warn('accordion is now deprecated. Use uib-accordion instead.');
        }
      }
    };
  }])

  .directive('accordionGroup', ['$log', '$accordionSuppressWarning', function($log, $accordionSuppressWarning) {
    return {
      require: '^accordion',         // We need this directive to be inside an accordion
      restrict: 'EA',
      transclude: true,              // It transcludes the contents of the directive into the template
      replace: true,                 // The element containing the directive will be replaced with the template
      templateUrl: function(element, attrs) {
        return attrs.templateUrl || 'template/accordion/accordion-group.html';
      },
      scope: {
        heading: '@',   //傳遞字符串值            // Interpolate the heading attribute onto this scope
        isOpen: '=?',  //=雙向綁定
        isDisabled: '=?'  //=雙向綁定
      },
      controller: function() { //讓這個指令的heading等于傳入的參數(shù)
        this.setHeading = function(element) {
          this.heading = element;
        };
      },
      link: function(scope, element, attrs, accordionCtrl) {
        if (!$accordionSuppressWarning) {
          $log.warn('accordion-group is now deprecated. Use uib-accordion-group instead.');
        }

        accordionCtrl.addGroup(scope);

        scope.openClass = attrs.openClass || 'panel-open';
        scope.panelClass = attrs.panelClass;
        scope.$watch('isOpen', function(value) {
          element.toggleClass(scope.openClass, !!value);
          if (value) {
            accordionCtrl.closeOthers(scope);
          }
        });

        scope.toggleOpen = function($event) {
          if (!scope.isDisabled) {
            if (!$event || $event.which === 32) {
              scope.isOpen = !scope.isOpen;
            }
          }
        };
      }
    };
  }])

  .directive('accordionHeading', ['$log', '$accordionSuppressWarning', function($log, $accordionSuppressWarning) {
    return {
      restrict: 'EA',
      transclude: true,   // Grab the contents to be used as the heading
      template: '',       // In effect remove this element!
      replace: true,
      require: '^accordionGroup',
      link: function(scope, element, attr, accordionGroupCtrl, transclude) {
        if (!$accordionSuppressWarning) {
          $log.warn('accordion-heading is now deprecated. Use uib-accordion-heading instead.');
        }
        // Pass the heading to the accordion-group controller
        // so that it can be transcluded into the right place in the template
        // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
        accordionGroupCtrl.setHeading(transclude(scope, angular.noop));
      }
    };
  }])

  .directive('accordionTransclude', ['$log', '$accordionSuppressWarning', function($log, $accordionSuppressWarning) {
    return {
      require: '^accordionGroup',
      link: function(scope, element, attr, controller) {
        if (!$accordionSuppressWarning) {
          $log.warn('accordion-transclude is now deprecated. Use uib-accordion-transclude instead.');
        }

        scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) {
          if (heading) {
            element.find('span').html('');
            element.find('span').append(heading);
          }
        });
      }
    };
  }]);
*/
//具體內(nèi)容展示模塊潮秘,沒有獨立scope琼开,與父級使用同一個scope
angular.module('ui.bootstrap.collapse', [])
//<div class="panel-collapse collapse" uib-collapse="!isOpen">的指令
  .directive('uibCollapse', ['$animate', '$injector', function($animate, $injector) {
    var $animateCss = $injector.has('$animateCss') ? $injector.get('$animateCss') : null;//判斷是否有$animateCss服務注入易结,如果有就取得這個服務
    return {
      link: function(scope, element, attrs) {//link函數(shù)
          //展開函數(shù)
        function expand() {
          element.removeClass('collapse') 
            .addClass('collapsing')
            .attr('aria-expanded', true)//aria-expanded表示展開狀態(tài)枕荞。默認為undefined, 表示當前展開狀態(tài)未知。這里表示展開
            .attr('aria-hidden', false);//這里表示關閉

          if ($animateCss) {//如果有$animateCss服務搞动,就用來添加動畫
            $animateCss(element, {
              addClass: 'in',//in樣式就是block
              easing: 'ease',
              to: { height: element[0].scrollHeight + 'px' }
            }).start().finally(expandDone);
          } else {//如果沒有就用ng自帶的動畫模塊
            $animate.addClass(element, 'in', {
              to: { height: element[0].scrollHeight + 'px' }
            }).then(expandDone);//返回一個promise對象躏精,用then來處理成功回調(diào)
          }
        }
        //展開后回調(diào)
        function expandDone() {//具體的成功回調(diào)函數(shù),用來操作class
          element.removeClass('collapsing')
            .addClass('collapse')//display:none
            .css({height: 'auto'});
        }
        //收縮函數(shù)
        function collapse() {
          if (!element.hasClass('collapse') && !element.hasClass('in')) {//如果element沒有collapse樣式鹦肿,并且也沒有in樣式
            return collapseDone();
          }

          element
            // IMPORTANT: The height must be set before adding "collapsing" class.
            // Otherwise, the browser attempts to animate from height 0 (in
            // collapsing class) to the given height here.
            .css({height: element[0].scrollHeight + 'px'}) //設置高度
            // initially all panel collapse have the collapse class, this removal
            // prevents the animation from jumping to collapsed state
            .removeClass('collapse') //移除collapse矗烛,也就是移除display:none
            .addClass('collapsing')  //添加collapsing,高度0
            .attr('aria-expanded', false)
            .attr('aria-hidden', true);

          if ($animateCss) {
            $animateCss(element, {
              removeClass: 'in',
              to: {height: '0'}
            }).start().finally(collapseDone);
          } else {
            $animate.removeClass(element, 'in', {//設置動畫箩溃,高度為0
              to: {height: '0'}
            }).then(collapseDone);
          }
        }
        //收縮后回調(diào)函數(shù)
        function collapseDone() {
          element.css({height: '0'}); // Required so that collapse works when animation is disabled 動畫不執(zhí)行時運行
          element.removeClass('collapsing')//collapsing設置高度為0
            .addClass('collapse');//display:none
        }
        //監(jiān)聽attrs.uibCollapse也就是!isOpen的值瞭吃,來判斷展開和關閉
        scope.$watch(attrs.uibCollapse, function(shouldCollapse) { 
          if (shouldCollapse) {
            collapse();
          } else {
            expand();
          }
        });
      }
    };
  }]);

/* Deprecated collapse below 
 dead code
angular.module('ui.bootstrap.collapse')

  .value('$collapseSuppressWarning', false)

  .directive('collapse', ['$animate', '$injector', '$log', '$collapseSuppressWarning', function($animate, $injector, $log, $collapseSuppressWarning) {
    var $animateCss = $injector.has('$animateCss') ? $injector.get('$animateCss') : null;
    return {
      link: function(scope, element, attrs) {
        if (!$collapseSuppressWarning) {
          $log.warn('collapse is now deprecated. Use uib-collapse instead.');
        }

        function expand() {
          element.removeClass('collapse')
            .addClass('collapsing')
            .attr('aria-expanded', true)
            .attr('aria-hidden', false);

          if ($animateCss) {
            $animateCss(element, {
              easing: 'ease',
              to: { height: element[0].scrollHeight + 'px' }
            }).start().done(expandDone);
          } else {
            $animate.animate(element, {}, {
              height: element[0].scrollHeight + 'px'
            }).then(expandDone);
          }
        }

        function expandDone() {
          element.removeClass('collapsing')
            .addClass('collapse in')
            .css({height: 'auto'});
        }

        function collapse() {
          if (!element.hasClass('collapse') && !element.hasClass('in')) {
            return collapseDone();
          }

          element
            // IMPORTANT: The height must be set before adding "collapsing" class.
            // Otherwise, the browser attempts to animate from height 0 (in
            // collapsing class) to the given height here.
            .css({height: element[0].scrollHeight + 'px'})
            // initially all panel collapse have the collapse class, this removal
            // prevents the animation from jumping to collapsed state
            .removeClass('collapse in')
            .addClass('collapsing')
            .attr('aria-expanded', false)
            .attr('aria-hidden', true);

          if ($animateCss) {
            $animateCss(element, {
              to: {height: '0'}
            }).start().done(collapseDone);
          } else {
            $animate.animate(element, {}, {
              height: '0'
            }).then(collapseDone);
          }
        }

        function collapseDone() {
          element.css({height: '0'}); // Required so that collapse works when animation is disabled
          element.removeClass('collapsing')
            .addClass('collapse');
        }

        scope.$watch(attrs.collapse, function(shouldCollapse) {
          if (shouldCollapse) {
            collapse();
          } else {
            expand();
          }
        });
      }
    };
  }]);
*/
    
angular.module("template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache) {
  $templateCache.put("template/accordion/accordion-group.html",
    "<div class=\"panel {{panelClass || 'panel-default'}}\">\n" +
    "  <div class=\"panel-heading\" ng-keypress=\"toggleOpen($event)\">\n" +
    "    <h4 class=\"panel-title\">\n" +
    "      <a href tabindex=\"0\" class=\"accordion-toggle\" ng-click=\"toggleOpen()\" uib-accordion-transclude=\"heading\"><span ng-class=\"{'text-muted': isDisabled}\">{{heading}}</span></a>\n" +
    "    </h4>\n" +
    "  </div>\n" +
    "  <div class=\"panel-collapse collapse\" uib-collapse=\"!isOpen\">\n" +
    "     <div class=\"panel-body\" ng-transclude></div>\n" +
    "  </div>\n" +
    "</div>\n" +
    "");
}]);

angular.module("template/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {
  $templateCache.put("template/accordion/accordion.html",
    "<div class=\"panel-group\" ng-transclude></div>");
}]);

<div ng-controller="AccordionDemoCtrl">
  <script type="text/ng-template" id="group-template.html">
    <div class="panel {{panelClass || 'panel-default'}}">
      <div class="panel-heading">
        <h4 class="panel-title" style="color:#fa39c3">
          <a href tabindex="0" class="accordion-toggle" ng-click="toggleOpen()" uib-accordion-transclude="heading"><span
            ng-class="{'text-muted': isDisabled}">{{heading}}</span></a>
        </h4>
      </div>
      <div class="panel-collapse collapse" uib-collapse="!isOpen">
        <div class="panel-body" style="text-align: right" ng-transclude></div>
      </div>
    </div>
  </script>

  <p>
    <button type="button" class="btn btn-default btn-sm" ng-click="status.open = !status.open">Toggle last panel</button>
    <button type="button" class="btn btn-default btn-sm" ng-click="status.isFirstDisabled = ! status.isFirstDisabled">Enable / Disable first panel</button>
  </p>

  <div class="checkbox">
    <label>
      <input type="checkbox" ng-model="oneAtATime">
      Open only one at a time
    </label>
  </div>
  <uib-accordion close-others="oneAtATime">
    <uib-accordion-group heading="Static Header, initially expanded" is-open="status.isFirstOpen" is-disabled="status.isFirstDisabled">
      This content is straight in the template.
    </uib-accordion-group>
    <uib-accordion-group heading="{{group.title}}" ng-repeat="group in groups">
      {{group.content}}
    </uib-accordion-group>
    <uib-accordion-group heading="Dynamic Body Content">
      <p>The body of the uib-accordion group grows to fit the contents</p>
      <button type="button" class="btn btn-default btn-sm" ng-click="addItem()">Add Item</button>
      <div ng-repeat="item in items">{{item}}</div>
    </uib-accordion-group>
    <uib-accordion-group heading="Custom template" template-url="group-template.html">
      Hello
    </uib-accordion-group>
    <uib-accordion-group heading="Delete account" panel-class="panel-danger">
      <p>Please, to delete your account, click the button below</p>
      <button class="btn btn-danger">Delete</button>
    </uib-accordion-group>
    <uib-accordion-group is-open="status.open">
      <uib-accordion-heading>
        I can have markup, too! <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': status.open, 'glyphicon-chevron-right': !status.open}"></i>
      </uib-accordion-heading>
      This is just some content to illustrate fancy headings.
    </uib-accordion-group>
  </uib-accordion>
</div>
angular.module('ui.bootstrap.demo').controller('AccordionDemoCtrl', function ($scope) {
  $scope.oneAtATime = true;
  $scope.groups = [
    {
      title: 'Dynamic Group Header - 1',
      content: 'Dynamic Group Body - 1'
    },
    {
      title: 'Dynamic Group Header - 2',
      content: 'Dynamic Group Body - 2'
    }
  ];
  $scope.items = ['Item 1', 'Item 2', 'Item 3'];
  $scope.addItem = function() {
    var newItemNo = $scope.items.length + 1;
    $scope.items.push('Item ' + newItemNo);
  };
  $scope.status = {
    isFirstOpen: true,
    isFirstDisabled: false
  };
});

第一部分是angular插件的源碼,后面是官網(wǎng)的示例(https://angular-ui.github.io/bootstrap/)涣旨。
插件最核心的就是實現(xiàn)不同指令間的通信歪架,這個插件實現(xiàn)的方式是讓兩個作用域,UibAccordionController和uibCollapse這兩個控制器下的作用域下的實現(xiàn)通信霹陡。通信的方式是利用父子指令間和蚪,通過scope繼承實現(xiàn)的止状。分別繼承(雙向綁定)heading\isOpen\isDisabled三個參數(shù)。然后在分別的指令中對isOpen進行監(jiān)聽攒霹,就可以得到不同的效果怯疤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市催束,隨后出現(xiàn)的幾起案子集峦,更是在濱河造成了極大的恐慌,老刑警劉巖泣崩,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件少梁,死亡現(xiàn)場離奇詭異,居然都是意外死亡矫付,警方通過查閱死者的電腦和手機凯沪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來买优,“玉大人妨马,你說我怎么就攤上這事∩庇” “怎么了烘跺?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長脂崔。 經(jīng)常有香客問我滤淳,道長,這世上最難降的妖魔是什么砌左? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任脖咐,我火速辦了婚禮,結(jié)果婚禮上汇歹,老公的妹妹穿的比我還像新娘屁擅。我一直安慰自己,他們只是感情好产弹,可當我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布派歌。 她就那樣靜靜地躺著,像睡著了一般痰哨。 火紅的嫁衣襯著肌膚如雪胶果。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天斤斧,我揣著相機與錄音早抠,去河邊找鬼。 笑死折欠,一個胖子當著我的面吹牛贝或,可吹牛的內(nèi)容都是我干的吼过。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼咪奖,長吁一口氣:“原來是場噩夢啊……” “哼盗忱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起羊赵,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤趟佃,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后昧捷,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闲昭,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年靡挥,在試婚紗的時候發(fā)現(xiàn)自己被綠了序矩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡跋破,死狀恐怖簸淀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情毒返,我是刑警寧澤租幕,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站拧簸,受9級特大地震影響劲绪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜盆赤,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一贾富、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧弟劲,春花似錦祷安、人聲如沸姥芥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凉唐。三九已至庸追,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間台囱,已是汗流浹背淡溯。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留簿训,地道東北人咱娶。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓米间,卻偏偏與公主長得像,于是被迫代替她去往敵國和親膘侮。 傳聞我的和親對象是個殘疾皇子屈糊,可洞房花燭夜當晚...
    茶點故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容