# 图标选择后点亮

<!--angular代码-->
<span *ngFor="let item of itemList">
    <img
         [src]="idx===selectIndex ? iconSelect : icon"
         (click)="()=>{selectIndex=idx}"
    />
</span>
定义变量selectIndex,当其等于原坐标的时候,使用点击时的图标

# tab栏置于底部

/*对于跟组件*/
{
    height:100%;
}
/*对于跟组件中,底部tar栏上面的组件,通常是路由*/
{
    display:flex;
    flex-direction:column;
    align-items:stretch;
    flex:1;
}
/*布局结束后,底部栏会被撑到最下方*/

# 垂直网格布局

/*容器样式[容器组件]*/
{
  padding: 5px 0;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  display: grid;
  grid-auto-flow: row;//溢出时新增一行
  place-content: stretch;
  place-items: center;
  overflow-x: hidden;
  overflow-y: auto;
    
}

在组件中设置变量

<!--angular代码-->
<div
  class="grid-container"
  [ngStyle]="{
    'grid-template-rows': templateRows,
    'grid-template-columns': templateColumns,
    'grid-gap': gridGap
  }"
>
  <ng-content></ng-content>
</div>

在逻辑中设置

export class VerticalGridComponent implements OnInit {
  @Input() itemWidth = '4rem';
  @Input() itemHeight = '4rem';
  @Input() gridGap = '5px';
  constructor() {}

  ngOnInit() {}
  /* 响应式布局网格,auto-fill 用来在空间足够时尽可能的填充该位置,minmax 是最小和最大的宽度 */
  get templateRows() {
    return `minmax(auto-fill, ${this.itemHeight})`;
  }
  /**
   * CSS Grid Layout 的模版列表达式
   */
  get templateColumns() {
    return `repeat(auto-fill, minmax(${this.itemWidth}, 1fr))`;
  }
}

调用时,通过该百年itemWidth的值来决定每行显示几列。例如本例中itemWidth10rem就是两列20rem就是一列

<app-vertical-grid [itemWidth]="'20rem'" [itemHeight]="'2rem'">
  <div></div>
</app-vertical-grid>

# 设置在一个盒子内的上下滚动

通常在一个app中,底部的栏是固定的,但是上面是可滚动的长页面

/*host为整个页面的样式*/
:host {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  flex: 1;
  overflow-y: hidden;
}
/* 让中间部分可滚动,需要计算高度,页面高度减去头部和尾部 */
/*main为中间内容*/
.main {
  flex-grow: 1;
  overflow-y: auto;
  overflow-x: hidden;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
  height: calc(100% - 3rem);
}

# 卡片

网格布局并不是一个元素只能占一个格子。

例如我们将创建一个左面为图片,右面从上到下分别是简介、标签、价格的卡片。

.container {
  /*卡片的容器*/
  display: grid;
  grid-template-columns: 10rem 1fr;//每一列的尺寸
  grid-template-rows: 3rem 1fr 1rem 2rem;//每一排的尺寸
  grid-gap: 5px; //格子之间间隔
  grid-template-areas://区域划分,‘.’代表无内容
    'image title'
    'image .'
    'image tags'
    'image price';
  place-content: stretch;//是align-content(垂直格子和间隔如何分布)justify-content(水平格子和间隔如何分布)的简写
  place-items: stretch;//是align-items(内容在格子里垂直如何分布,stretch为内容占满格子)justify-items(内容在格子里水平如何分布)的简写
}
.product-image {
  grid-area: image;
  object-fit: contain;
  width: 9rem;
  height: 9rem;
}
.product-title {
  grid-area: title;
}
.product-tags {
  grid-area: tags;
}
.product-price {
  grid-area: price;
}

# 轮播图

模板为

<!--angular语法-->
<div class="container" [ngStyle]="{ height: sliderHeight }">##控制轮播图片的高度
<div class="image-slider" (scroll)="handleScroll($event)" #imageSlider>##滑动时触发事件
  <img
    *ngFor="let slider of sliders"
    [src]="slider.imgUrl"
    [alt]="slider.caption"
  />
</div>
<div class="nav-section">
  <span
    *ngFor="let _ of sliders; let idx = index"
    class="slide-button"
    [ngClass]="{ 'slide-button-select': idx === selectedIndex }"
  >
  </span>
</div>
</div>

样式为

.container {
  position: relative;
  overflow: hidden;
}

.container .image-slider {
  display: flex;
  overflow-x: scroll;
  scroll-snap-type: x mandatory;/*在x轴添加吸附效果*/
  scroll-behavior: smooth;/*使得元素的移动产生移动效果*/
  -webkit-overflow-scrolling: touch;/*在手机上可以通过触摸滚动*/
}

.container img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  scroll-snap-align: start;/*吸附参考标准*/
}

.nav-section {
  position: absolute;
  bottom: 0;
  width: 100%;
  opacity: 0.5;
  color: #fff;
  background-color: #000;
  display: flex;
  justify-content: flex-end;
  align-items: stretch;
}

.nav-section .slide-button {
  display: flex;
  width: 10px;
  height: 10px;
  background-color: #fff;
  text-decoration: none;
  border-radius: 50%;
  margin: 5px;
}
.container .image-slider::-webkit-scrollbar {
  display: none;
  width: 0 !important;
}

.nav-section .slide-button-select {
  background-color: #e02f29;
}

逻辑为

import {
  Component,
  OnInit,
  Input,
  ViewChild,
  ElementRef,
  Renderer2,
  AfterViewInit,
  OnDestroy,
  ChangeDetectionStrategy
} from '@angular/core';

export interface ImageSlider {
  id: number;
  imgUrl: string;
  link: string;
  caption: string;
}

@Component({
  selector: 'app-image-slider',
  templateUrl: './image-slider.component.html',
  styleUrls: ['./image-slider.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ImageSliderComponent implements OnInit, AfterViewInit, OnDestroy {
  @Input() sliders: ImageSlider[] = [];/*外部传入的图片的相关数据*/
  @Input() sliderHeight = '160px';
  @Input() intervalBySeconds = 2;
  @ViewChild('imageSlider', { static: true })
  imgSlider: ElementRef;/*取到名为imgSlider的元素数*/
  selectedIndex = 0;
  constructor(private rd2: Renderer2) {}
  intervalId;
  ngOnInit() {}

  ngAfterViewInit(): void {
    if (this.intervalBySeconds <= 0) {
      return;
    }
    this.intervalId = setInterval(() => {
      this.rd2.setProperty(/*添加属性*/
        this.imgSlider.nativeElement,/*对应的图片容器元素*/
        'scrollLeft',/*向左移动的距离*/
        (this.getIndex(++this.selectedIndex) *
          this.imgSlider.nativeElement.scrollWidth) /
          this.sliders.length/*计算得到现在应向左移动的距离*/
      );
    }, this.intervalBySeconds * 1000);
  }

  ngOnDestroy(): void {
    clearInterval(this.intervalId);/*解决内存泄漏*/
  }

  getIndex(idx: number): number {
    /*获取现在应该是第几张图*/
    return idx >= 0
      ? idx % this.sliders.length
      : this.sliders.length - (Math.abs(idx) % this.sliders.length);
  }

  handleScroll(ev) {
    /*在手动滑动轮播图后,更改this.selectedIndex。如果没有此函数,例如图片在2,手动划到了1,下一次,图片仍然自动划到3*/
    const ratio =
      ev.target.scrollLeft / (ev.target.scrollWidth / this.sliders.length);
    this.selectedIndex = Math.round(ratio);
  }
}

# 两栏布局,左栏固定,右栏滚动(常见开放文档页面)

使用fixed布局

.left{
    position:fixed;
    width:200px;
    left:0;
    top:0;
}
.right{
    position: relative;
    marginLift:200px;
}

将左栏黏贴

.left{
    /*height: calc(100vh - 90px);//常用来设置高度*/
    top: 0;
    float:left;
    position: sticky;/*将其粘帖在某个地方不动*/
    position: -webkit-sticky;
}
.right{
    float:left;
}

sticky:

元素根据正常文档流进行定位,然后相对它的*最近滚动祖先(nearest scrolling ancestor)*和 containing block (opens new window) (最近块级祖先 nearest block-level ancestor),包括table-related元素,基于top, right, bottom, 和 left的值进行偏移。偏移值不会影响任何其他元素的位置。

该值总是创建一个新的层叠上下文(stacking context)。注意,一个sticky元素会“固定”在离它最近的一个拥有“滚动机制”的祖先上(当该祖先的overflowhidden, scroll, auto, 或 overlay时),即便这个祖先不是真的滚动祖先。这个阻止了所有“sticky”行为

sticky生效条件:

1、必须指定top、bottom、left、right其中的一个

2、达到设定阔值,top为0时与fixed相同,top大于0时,加成relative属性

fixed与sticky的区别:

sticky定位可以被认为是relative和fixed的混合。粘性定位的元素被视为相对定位,直到它超过指定的阈值,此时它被视为固定的,直到它到达其父母的边界。