Angular实现双向折叠列表组件的示例代码

最近在做一个双向折叠组件,如下图所示,页面是分为两组,左边页面是Summary Panel,主要是一组列表,右边页面是Detail Panel,展示左边列表中某一项的具体信息,我们把它记作“Middle State”。

我们还看到有“<”和“>”两组按钮,这就是我们要做的“双向折叠组件”。点击左边的“<”,Summary Panel折叠起来,Detail Panel铺满整个页面,我们把它记作“Left State”,如下图:

在Summary Panel折叠状态下,点击“>”,又回到“Middle State”。点击“>”,Detail Panel折叠起来,Summary Panel铺满整个页面,我们把它记作“Right State”,如下图:

我们通过以上的需求分析可知,

1.页面的总体布局是一个Summary的div,两个箭头buttons,一个Detail的div。

2.页面总共有三种state:“Middle”、“Left”、“Right”,有两个button:“<”和“>”,也就是两个button去控制三个state。

因此我们需要定义一个枚举来记录页面的三种状态(注意,定义枚举要用export导出,否则后面会出错)

export enum CollapseExpandState {
  Middle = 1,
  Left,
  Right
}

页面的结构如下,并且通过一个变量_collapseExpandState去控制“left”和“right”两个button,具体为“<”会在页面状态为“Middle”和“Right”的情况下出现,“>”会在页面状态为“Middle”和“Left”状态下出现,从需求图中即可得知:

<div id="container">
  <div id="summary"></div>
  <div id="buttons">
    <div id="left" *ngIf="_collapseExpandState === CollapseExpandState.Middle || CollapseExpandState.Right" (click)="_onHandleLeft($event)">《</div>
    <div id="right"> *ngIf="_collapseExpandState === CollapseExpandState.Middle || CollapseExpandState.Left" (click)="_onHandleLeft($event)">》</div>
  </div>
  <div id="detail"></div>
</div>

这里在angular的template中用到了枚举,遭遇了一些麻烦,如果我们按上述定义了枚举,并且在Angular Component的template中用了枚举,我们会得到以下的错误提示:

TypeError: Cannot read property 'Middle' of undefined

也就是说,在Angular2的template中无法识别定义的枚举类型CollapseExpandState,这是因为你写的Angular Component的template模板的执行环境是你定义的component class,但是在class中并没有关于CollapseExpandState枚举的任何引用,所以Angular在为你的component生成模板的时候认为CollapseExpandState是undefined的。知道了原因,解决方案就很容易了,只需要在component class中加入这个枚举的引用即可:

@component(...)
export class ContainerWidget {
  public CollpaseExpandState: any = CollapseExpandState;
}

我们通过枚举状态来控制了两个buttons是否在恰当的页面状态显示与否,但是即使是同一个buttons,在不同的页面状态下所用到的样式也会不同,这里的样式其实最主要的就是位置了。我们先来考虑如何去控制button的样式,再来考虑如何去正确定位不同页面状态下button的位置。

对于控制button的样式,我们需要控制三个样式:"left button"、"right button"还有“buttons”。能够想到有三种方案:

I、用ng-class

ng-class一般的用法如下:

<some-element [ngClass]="{'first': true, 'second': true, 'third': false}">...</some-element>

因此它需要用boolean去控制,每一种样式需要一个boolean去控制,left和right各有两种样式,buttons有三种样式,这样就需要用5个boolean去控制,略显麻烦。

II、 用ElementRef.nativeElement.className

分别在buttons、left和right上用模板变量,然后在class中定义:

@ViewChild("buttons") buttons: ElementRef;
@ViewChild("left") left: ElementRef;
@ViewChild("right") right: ElementRef;

在处理函数中这样去给class赋值从而改变样式:

this.left.nativeElement.className = "XXXXX";

这样的话,我们需要从元素的角度出发,只需要3个元素变量,从而改变元素上的className即可。但是这样做有个隐患,注意到我们是用的ngIf来控制left和right在不同状态下是否存在,因为每一次事件处理都需要对三个元素的样式进行赋值,但是如果某个页面状态下ngIf为false从而元素不存在,那么就会报“Null Pointer”的错误,所以如果所引用的元素受到了ngIf的控制,不确定是否一定存在的情况下,要慎用该方法为元素赋予样式。

III、 用class="{{}}"

为了II中的尴尬,我们采用在HTML元素上对class进行直接赋值的方式,但是需要借用插值表达式{{}}。我们在css中用class的形式定义好样式,并且在compoennt class中定义三个字符串变量记录className,然后在事件处理函数中把相应的className赋予变量即可。这样我们就不用担心元素是否存在而导致的空指针了。

考虑完如何控制样式,下面我们进入CSS样式的讨论,这里其实主要考虑的就是位置。

我们采用flex布局,从左到右依次排列Summary Panel, buttons和Detail Panel。我们希望Buttons向左移,但是空出的位置被Detail Panel来填充。首先来看一下不设样式的效果图:

显然buttons是占据了文档流的位置的,如果这时候我们用relative定位buttpms,并且设置left的值为-74px(注意到left为负数就会把元素往左推):

.buttons{
  display: flex;
  position: relative;
  margin-top: 23px;
  left: -74px;
}

效果图为:

发现如果用left的话,buttons原来的文档流位置依然存在,只是buttons相对于原来的位置移动了一定的位移。

如果我们用margin-left来设置呢:

.buttons{
  display: flex;
  position: relative;
  margin-top: 23px;
  margin-left: -74px;
}

效果图为:

它和left不同之处在于,left会留住原来的文档流位置,但是用margin-left原来的文档流位置会消失,而由后面的元素补充过来,而我们想要的效果,正好是用margin-left来实现的。

所以用CSS定位的时候,要明白left和margin-left的区别,从而选择正确的方式来定位。

总结一下,从这个案例中我们学习到了:

  1. 双向折叠可以用“3种页面状态去控制2个按钮”来实现
  2. enum在Angular Component的template中用到时,需要在compnent class中添加它的引用
  3. 控制元素样式有很多方法,要选择合适的方法
  4. CSS定位中left和margin-left虽然都能把元素推向左边,但是left保留原来文档流位置,margin-left不保留原来文档流位置。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • AngularJS折叠菜单实现方法示例

    本文实例讲述了AngularJS折叠菜单实现方法.分享给大家供大家参考,具体如下: <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="bootstrap.min.css&quo

  • Angular实现双向折叠列表组件的示例代码

    最近在做一个双向折叠组件,如下图所示,页面是分为两组,左边页面是Summary Panel,主要是一组列表,右边页面是Detail Panel,展示左边列表中某一项的具体信息,我们把它记作"Middle State". 我们还看到有"<"和">"两组按钮,这就是我们要做的"双向折叠组件".点击左边的"<",Summary Panel折叠起来,Detail Panel铺满整个页面,我们把它记

  • 基于vue的tab-list类目切换商品列表组件的示例代码

    在大多数电商场景中,页面都会有类目切换加上商品列表的部分,页面大概会长这样 每次写类似场景的时候,都需要去为类目商品列表写很多逻辑,为了提高开发效率我决定将这一部分抽离成组件. 实现 1.样式 所有tab栏的样式和商品列表的样式都提供插槽,供业务自己定制 2.变量 isTabFixed: false,//是否吸顶 tab: 1,//当前tab page: 1,//当前页数 listStatus: { finished: false,//是否已是最后一页 loading: false,//是否加载

  • Angular+ionic实现折叠展开效果的示例代码

    1,html中 <ion-item> <div class="middle-content-order"> <div class="middle-order-icon"> <ion-icon name="chevron-up-outline" class="up-gray" item-right *ngIf="!isShow" (click)="isSho

  • 原生JavaScript实现弹幕组件的示例代码

    前言 如今几乎所有的视频网站都有弹幕功能,那么今天我们就自己用原生 JavaScript 封装一个弹幕类.这个类希望有如下属性和实例方法: 属性 el容器节点的选择器,容器节点应为绝对定位,设置好宽高 height 每条弹幕的高度 mode 弹幕模式,half则为一半容器高度,top为三分之一,full为占满 speed弹幕划过屏幕的时间 gapWidth后一条弹幕与前一条弹幕的距离 方法 pushData 添加弹幕元数据 addData持续加入弹幕 start开始调度弹幕 stop停止弹幕 r

  • 使用Vue3实现一个Upload组件的示例代码

    通用上传组件开发 开发上传组件前我们需要了解: FormData上传文件所需API dragOver文件拖拽到区域时触发 dragLeave文件离开拖动区域 drop文件移动到有效目标时 首先实现一个最基本的上传流程: 基本上传流程,点击按钮选择,完成上传 代码如下: <template> <div class="app-container"> <!--使用change事件--> <input type="file" @ch

  • vue中使用element日历组件的示例代码

    先看下效果图: 完整代码附上 <template> <div class="newSeeds" id="famerCalendar"> <div class="title-bottom"> <el-date-picker :clearable="false" prefix-icon="timeFilter" v-model="value2" ty

  • Flutter实现单选,复选和开关组件的示例代码

    目录 1.开关 Switch 2.单选 Radio 3.复选多选 Checkbox 小结 1.开关 Switch 构造方法: const Switch({ Key? key, required this.value,//当前开关状态 required this.onChanged,// 改变状态回调 this.activeColor,// 开启全部颜色 this.activeTrackColor,// 开启轨道的颜色 this.inactiveThumbColor,//关闭滑块颜色 this.i

  • 微信小程序实现自定义弹窗组件的示例代码

    目录 编写组件代码 Dialog.wxml Dialog.js Dialog.wxss 调用自定义组件 上一篇中说的是小程序自带的弹窗组件,今天,我们来试试小程序的自定义组件,我们自定义一个带确定取消的弹窗组件. 首先,放一下,最终的效果图: 这是我们最后要实现的效果 那么,首先,我们创建一个组件 新建component文件夹存放我们的组件,里边存放的就是我们所用的组件,我们今天要做的事弹出框,新建文件夹popup存放我们的组件模板,点击右键选择新建component,就会自动生成组件的模板wx

  • Android Flutter实现上拉加载组件的示例代码

    前言 在此之前对列表下拉刷新做了调整方案,具体介绍可以阅读下拉刷新组件交互调整.既然列表有下拉刷新外当然还有上拉加载更多操作了,本次就来介绍如何为列表增加上拉加载更多的交互实现. 实现方案 上拉刷新实现形式上可以有多种实现方式,若不带交互形式可采用NotificationListener组件监听滑动来实现上拉加载更多:如果对操作交互上有一定要求期望上拉刷新带有直观动画可操作性就需要实现一定样式来实现了. 监听NotificationListener实现 NotificationListener(

  • 开发Vue树形组件的示例代码

    本文介绍了Vue树形组件的示例代码,分享给大家,具体如下: 使用SemanticUI和vue做一个menubar组件,实现方法大概是这样的: <template> <div class="ui menu"> <template v-for="item in leftItems"> <a " v-if="!item.children" @click="item.click"&g

随机推荐