[Angular 基础] - routing 路由(下)

[Angular 基础] - routing 路由(下)


之前部分 Angular 笔记:

  • [Angular 基础] - 自定义指令,深入学习 directive

  • [Angular 基础] - service 服务

  • [Angular 基础] - routing 路由(上)


使用 route

书接上回,继续折腾 routing

按照最初的 wireframe,它的实现是这样的:

在这里插入图片描述

之前为了简化一些实现,就直接采取了在 routes 下面声明一个新的路径,去采用重新渲染子组件的方式去进行重定向。这也会有几个比较麻烦的点:

  1. 数据渲染不完全
  2. servers/:id 返回到 servers 很麻烦

如果想要解决这个问题,将子组件重新渲染:

<div class="col-xs-12 col-sm-4">
  <app-edit-server></app-edit-server>
  <hr />
  <app-server></app-server>
</div>

又会遇到下面这些问题:

  1. 在主界面时代码抛出异常

    在这里插入图片描述

    有些情况 Cannot read properties of undefined 是会 break 页面,从而导致内容无法渲染的情况

    会有这个问题也是因为子页面尚未被选中,路径还是 http://localhost:4200/servers,自然无法获取对应的 server 数据

  2. 渲染了额外数据

    理想条件下,当在 /servers 这个路径下,代表着没有任何的服务器被选中,那么也不应该渲染对应的组件

为了更加优雅的解决这个问题,而不是使用大量的 ngIf 去进行条件控制,Angular 提供了 child/nested routes 的解决方案

child route

突然想到, react-router v6 也实现了这个功能……果然这日子还是到了前端框架互相抄的日子了……

这里具体修改的配置如下:

  • routing module

    const appRoutes: Routes = [
      {
        path: 'servers',
        component: ServersComponent,
        children: [
          {
            path: ':id',
            component: ServerComponent,
          },
          {
            path: ':id/edit',
            component: EditServerComponent,
          },
        ],
      },
    ];
    
  • servers V 层

    <div class="row">
      <div class="col-xs-12 col-sm-4">
        <div class="list-group">
          <a
            [routerLink]="['/servers', server.id]"
            [queryParams]="{ allowEdit: server.id === 3 ? '1' : '0' }"
            fragment="loading"
            class="list-group-item"
            *ngFor="let server of servers"
          >
            {{ server.name }}
          </a>
        </div>
      </div>
      <div class="col-xs-12 col-sm-4">
        <router-outlet></router-outlet>
      </div>
    </div>
    

实现后的效果:

在这里插入图片描述

就像是在 appRoutes 中定义的一样,一旦路径为 servers/:id,那么就会渲染单独的 server component,如果路径是 servers/:id/edit,就会渲染 edit-server component

我的理解是,一旦将对应的组件放到了 children 中,就会形成以父组件为基础的一个单独模块。Angular 就像处理其他模块一样,都需要通过一个 router-outlet 去进行监听,才能做出合适的反应

如果 V 层没有添加 router-outlet 的话,那么 children 中的模块就不会被渲染

更多 query param 的部分

上面的动图其实还有一个问题,那就是当从 servers/:id 定向到 servers/:id/edit 时,后置的 query parameters 全都丢了,这也是 Angular 的默认行为,想要改变这个行为,需要在 click handler 中进行处理,下面是对于 edit server 按钮的事件处理:

export class ServerComponent implements OnInit {
  onEdit() {
    this.router.navigate(['edit'], {
      relativeTo: this.route,
      queryParamsHandling: 'preserve',
    });
  }
}

这里的 queryParamsHandling 有三个值:

export declare type QueryParamsHandling = 'merge' | 'preserve' | '';
  • merge

    会将当前组件有的 query parameters 与已经存在的 query parameter 进行合并

  • preserve

    会保留已经存在的 query parameter

这时候的效果如下:

在这里插入图片描述

可以看到,allowEdit 这个参数被保留下来了,对应的 EditServerComponent 也可以通过当前的 query parameter 进行正常的逻辑处理

⚠️:EditServerComponent 有两个 subscription,一个 subscribe queryParams,另一个则是 subscribe 当前传来的 server id:

export class EditServerComponent implements OnInit {
  ngOnInit() {
    this.route.queryParams.subscribe((queryParams: Params) => {
      this.allowEdit = queryParams.allowEdit === '1';
    });
    this.route.fragment.subscribe();

    const id = parseInt(this.route.snapshot.params.id);

    // subscribe route params to update the id if params change
    this.server = this.serversService.getServer(id);
    this.serverName = this.server.name;
    this.serverStatus = this.server.status;

    this.route.params.subscribe((params: Params) => {
      this.server = this.serversService.getServer(parseInt(params.id));
      this.serverName = this.server.name;
      this.serverStatus = this.server.status;
    });
  }
}

添加 not found 页面

根据当前的实现,如果用户意外输入了一些错误的路径,那么就会重新导航到首页,并且在 console 中输出报错信息:

在这里插入图片描述

这也是一个相对而言比较粗暴的处理方式,大多数的应用都会渲染一个 not found 页面,而不是直接显示一个空白屏幕。接下来就更新 app routing module 进行实现:

const appRoutes: Routes = [
  // 其余处理不变
  { path: 'not-found', component: PageNotFoundComponent },
  { path: '**', redirectTo: '/not-found' },
];

⚠️:这里假设 Not Found 页面已经通过 ng generate component 被创建了,也实现了对应的 V 层

显示效果如下:

在这里插入图片描述

这里业务实现的逻辑也比较简单,首先是确定一个为 not-found 的路径,将对因渲染的组件设置为 PageNotFoundComponent。接下来就是终点的实现了,也就是一个 wildcard match,这个 match 必须 放在最下面,这样无法被之前路由 capture 的变化会落到这里,否则所有的页面都会渲染为 PageNotFoundComponent 组件。

当当前路由找不到当前提供的路径时,它就会被重新定向到 /not-found 页面,从而渲染 PageNotFoundComponent 组件

另一个稍微简单一点的处理方式就是直接将 **component: PageNotFoundComponent 进行绑定:{ path: '**', component: PageNotFoundComponent,这样就可以保留当前的路径,并渲染 PageNotFoundComponent 组件

这里有一点像是 React Router Dom v5 里的 Switch,不过 React Router Dom 里面的 wildcard 时 *,这里是 **

⚠️:Agular 的路径 match 是通过前缀实现的,在 not found page 这个案例的情况是 wildcard,不会造成任何的问题。

👀:一个使用情况可以从 '' 导航到 '/home,这时候配置可以这么写:{ path: '', redirectTo: 'home', patchMatch: 'full' },

Guards

guards 是用来控制路由的,博啊哭哦权限控制、是否能被访问等一些行为,每个 guard 都有不同的功能

canActive

这个 guard 用来控制当前路由是否可以被访问

这里以 servers 为例,条件控制为只有登录的用户才可以访问 /servers,变动如下:

  • routing module

    const appRoutes: Routes = [
      {
        path: 'servers',
        canActivate: [AuthGuardService],
        component: ServersComponent,
      },
    ];
    
  • 新增 AuthGuardService

    @Injectable({
    providedIn: 'root',
    })
    export class AuthGuardService implements CanActivate, CanActivateChild {
    constructor(private authService: AuthService, private router: Router) {}
    
    canActivate(
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
    ): Observable<boolean> | Promise<boolean> | boolean {
    
        return this.authService.isAuthenticated().then((authenticated: boolean) => {
    
        if (authenticated) {
            console.log('authenthenciated');
            return true;
        } else {
          console.log('not authenthenciated');
            this.router.navigate(['/']);
            return false;
        }
        });
    }
    

其中 isAuthenticated 的实现如下:

  isAuthenticated() {
    const promise = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(this.login);
      }, 1000);
    });

    return promise;
  }

展示效果如下:

在这里插入图片描述

这里 isAuthenticated 返回的永远是一个 promise,并且会在一秒钟后完成登陆,所以永远不会被重定向到首页。稍微代码,将 resolve 中改成 false,并修改一下冲定向的路径也可以实现一下效果:

在这里插入图片描述

这里都有一个 1s 的等待时间,这个是 setTimeout 决定的


需要注意的是 CanActivate 已经 deprecated 了,原因似乎也是 Angular 要走走 functional guard,而 functional guard 的实现如下:

这里的实现稍微复杂一些,

  1. 首先将 then 那一块代码抽出来,放到一个新的 service 中:

    @Injectable({
      providedIn: 'root',
    })
    export class PermissionsService {
      constructor(private authService: AuthService, private router: Router) {}
    
      canActivate(
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
      ): Observable<boolean> | Promise<boolean> | boolean {
        return this.authService
          .isAuthenticated()
          .then((authenticated: boolean) => {
            if (authenticated) {
              console.log('authenthenciated');
              return true;
            } else {
              console.log('not authenthenciated');
              this.router.navigate(['/forbidden']);
              return false;
            }
          });
      }
    }
    

    ⚠️:这里使用 canActivate 只是一个约定俗成的规范,它可以改成任何一个名称,不是一定要用 canActivate

  2. 使用 functional guard

    export const authGuardFunc: CanActivateFn = (route, state) => {
      return inject(PermissionsService).canActivate(route, state);
    };
    

    ⚠️:直接实现下面的代码,ide 不会报错,但是浏览器会报错:

    export const authGuardFunc: CanActivateFn = (route, state) => {
      return inject(AuthService)
        .isAuthenticated()
        .then((authenticated: boolean) => {
          if (authenticated) {
            console.log('authenthenciated');
            return true;
          } else {
            console.log('not authenthenciated');
            inject(PermissionsService).canActivate(route, state);
            return false;
          }
        });
    };
    

    在这里插入图片描述

canActiveChild

有一个情况就是,用户可以访问 servers,但是不能访问 servers 的 children。一个解决方法是将 canActivate: [AuthGuardService], cv 到每一个 child component,不过当 child component 变多的时候,管理就会变得非常的麻烦。

如果当前逻辑应用于所有的 child component,就可以使用 canActiveChild 去实现:

@Injectable({
  providedIn: 'root',
})
export class AuthGuardService implements CanActivate, CanActivateChild {
  constructor(private authService: AuthService, private router: Router) {}

  // 新增部分,可以直接调用之前实现的 canActivate
  canActivateChild(
    childRoute: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): boolean | Observable<boolean> | Promise<boolean> {
    return this.canActivate(childRoute, state);
  }
}

并在 routing module 中实现对应的修改:

const appRoutes: Routes = [
  {
    path: 'servers',
    canActivateChild: [AuthGuardService],
    // 其余部分省略
  },
];

效果如下:

在这里插入图片描述


同样,对应的 functional guard 的修改如下:

  1. permissions service 的修改:

    export class PermissionsService {
      constructor(private authService: AuthService, private router: Router) {}
    
      canActiveChild(
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
      ): Observable<boolean> | Promise<boolean> | boolean {
        return this.canActivate(route, state);
      }
    }
    
  2. func guard 的修改:

    export const authGuardFunc: CanActivateFn = (route, state) => {
      return inject(PermissionsService).canActivate(route, state);
    };
    
    export const authGuardChildFunc: CanActivateChildFn = (route, state) => {
      return inject(PermissionsService).canActiveChild(route, state);
    };
    

调用的时候则是直接在 canActivateChild 中放入 authGuardChildFunc 即可

鉴于代码完全一致,放入 authGuardFunc 也没问题啦……

canDeactivate

canDeactivate 是一个在离开当前页面时会触发的 guard,一般可以用来检查未保存的内容,防止用户提前离开

具体实现方式如下:

  1. 创造一个 service,具体实现如下:

    export interface CanComponentDeactivate {
      canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
    }
    
    @Injectable({
      providedIn: 'root',
    })
    export class CanDeactivateGuard
      implements CanDeactivate<CanComponentDeactivate>
    {
      canDeactivate(
        component: CanComponentDeactivate,
        currentRoute: ActivatedRouteSnapshot,
        currentState: RouterStateSnapshot,
        nextState: RouterStateSnapshot
      ): boolean | Observable<boolean> | Promise<boolean> {
        return component.canDeactivate();
      }
    }
    
  2. 在 routing module 中添加 guard:

    const appRoutes: Routes = [
      {
        path: 'servers',
        children: [
          {
            path: ':id/edit',
            component: EditServerComponent,
            canDeactivate: [CanDeactivateGuard],
          },
        ],
      },
    ];
    
  3. EditServerComponent 实现 canDeactivate 函数

    如果不实现的话,在离开当前页面会报错,也就 break project 了:

    在这里插入图片描述

    这也是为什么 Angular 的实现这么复杂……主要还是为了类型检查,以及 添加的功能都必须实现 这样的检查

    具体实现如下:

    @Component({
      selector: 'app-edit-server',
      templateUrl: './edit-server.component.html',
      styleUrls: ['./edit-server.component.css'],
    })
    export class EditServerComponent implements CanComponentDeactivate {
      serverName = '';
      serverStatus = '';
      allowEdit = false;
      changesSaved = false;
    
      canDeactivate(): boolean | Promise<boolean> | Observable<boolean> {
        if (!this.allowEdit) {
          return true;
        }
    
        if (
          (this.serverName !== this.server.name ||
            this.serverStatus !== this.server.status) &&
          !this.changesSaved
        ) {
          return confirm('Do you want to discard the changes?');
        } else {
          return true;
        }
      }
    }
    

实现完成后的效果:

在这里插入图片描述

这里有 3 种情况:

  1. 当用户没有编辑权限

    ✅ 直接允许重定向

  2. 当用户有编辑权限,但是用户 没有 编辑内容

    ✅ 直接允许重定向

  3. 当用户有编辑权限,并且用户 已经 编辑内容

    ❌ 不允许直接冲定向

    这里的具体操作是跳出一个 confirm,当用户确认后,即可重新定向


这里也提出 functional guard 的实现方式,鉴于其他的变量名不变,所以这里只需要修改 CanDeactivateGuard service 即可:

export interface CanComponentDeactivate {
  canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}

export const CanDeactivateGuard: CanDeactivateFn<CanComponentDeactivate> = (
  component: CanComponentDeactivate
): Observable<boolean> | boolean => {
  if (component.canDeactivate && component.canDeactivate()) return true;
};

// @Injectable({
//   providedIn: 'root',
// })
// export class CanDeactivateGuard
//   implements CanDeactivate<CanComponentDeactivate>
// {
//   canDeactivate(
//     component: CanComponentDeactivate,
//     currentRoute: ActivatedRouteSnapshot,
//     currentState: RouterStateSnapshot,
//     nextState: RouterStateSnapshot
//   ): boolean | Observable<boolean> | Promise<boolean> {
//     return component.canDeactivate();
//   }
// }
resolve

canActivate 是控制用户允许访问当前页面, canDeactivate 是控制用户不允许访问当前页面,resolve 则是允许等待一段时间(如获取数据的异步操作),在完成操作后渲染组件

实现如下:

  • 创建一个新的 resolver service

    interface Server {
      id: number;
      name: string;
      status: string;
    }
    
    @Injectable({
      providedIn: 'root',
    })
    export class ServerResolverService implements Resolve<Server> {
      constructor(private serversService: ServersService) {}
    
      resolve(
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
      ): Server | Observable<Server> | Promise<Server> {
        const promise: Promise<Server> = new Promise((resolve) => {
          setTimeout(() => {
            console.log('resolving');
    
            resolve(this.serversService.getServer(parseInt(route.params.id)));
          }, 1000);
        });
    
        return promise;
      }
    }
    

    这个 service 就是实现一个 resolver,即在组件渲染之前获取对应的 server。我这里用 setTimeout 模拟了一个异步操作

  • 更新 routing module

    这里制定要使用 resolver 的组件,即 servers/:id

    const routes = (Routes = [
      {
        path: 'servers',
        children: [
          {
            path: ':id',
            component: ServerComponent,
            resolve: { server: ServerResolverService },
          },
        ],
      },
    ]);
    

    这一步操作会将获取的 server——resolve 的数据——存储到 server 这个变量名中

  • 更新 server component

    export class ServerComponent implements OnInit {
      server: { id: number; name: string; status: string };
    
      ngOnInit() {
        this.route.data.subscribe((data: Data) => {
          console.log(data);
    
          this.server = data.server;
        });
      }
    }
    

    这里主要更新 ngOnInit 中的内容,最终的效果与实现的效果是一致的

最终效果:

在这里插入图片描述

可以看到渲染被延迟了大概一秒钟,然后输出了对应的 server


同样增添一下 functional guard 的实现:

export const serverResolver: ResolveFn<Server> = (route) => {
  const serverId = parseInt(route.params.id);

  return inject(ServersService).getServer(serverId);
};

⚠️:getServer 返回的是一个 Server

传输数据

之前在 canActivate guard 中创建了一个 forbidden 页面,这样每次页面报错都会重新导航到 /forbidden 上去。但是这样做的一个问题就在于,如果想要做更多的报错处理,那么可能需要创造更多的报错页面。

下面提供一个可以复用

下面是步骤:

  1. 创建一个新的 generic error 页面

    • V 层
    <h4>{{ errorMessage }}</h4>
    
  • VM 层

    @Component({
      selector: 'app-error-page',
      templateUrl: './error-page.component.html',
      styleUrl: './error-page.component.css',
    })
    export class ErrorPageComponent implements OnInit {
      errorMessage: string;
    
      constructor(private route: ActivatedRoute) {}
    
      ngOnInit() {
        this.errorMessage = this.route.snapshot.data['message'];
        this.route.data.subscribe((data: Data) => {
          this.errorMessage = data.message;
        });
      }
    }
    
  1. 修改 app routing

    const appRoutes: Routes = [
      {
        path: 'not-found',
        component: ErrorPageComponent,
        data: { message: 'Page not found!' },
      },
      {
        path: '**',
        redirectTo: '/not-found',
      },
    ];
    

效果如下:

在这里插入图片描述

这样可以创建多个不同的路径,并传输不同的信息,实现使用一个 ErrorPageComponent 渲染不同的报错信息

如果搭配其他的 Observable,这里应该也是可以实现避开重复声明路由,而是直接用 ** wildcard 去渲染 ErrorPageComponent,随后使用 Observable 获取报错信息

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/431410.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ffmpeg使用命令实现音视频分离

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、简单介绍二、具体操作三、验证1.源文件2.视频文件3.音频文件 四、补充总结 前言 有时候由于特殊需要可能需要将一个视频&#xff08;带音频&#xff09;的…

洛谷:P3068 [USACO13JAN] Party Invitations S(枚举、前缀和)

这题我们数据范围太大&#xff0c;用二维肯定是不行的&#xff0c;我们可以采用一维线性存储。 如题意&#xff0c;我们可以将每组奶牛编号都存在一维数组里面&#xff0c;只需记录每组的头尾指针就可以了。 如题中样例我们就可以存储成1 3 3 4 1 2 3 4 5 6 7 4 3 2 1 然后第…

docker部署aria2-pro

前言 我平时有一些下载视频和一些资源文件的需求&#xff0c;有时候需要离线下载&#xff0c;也要速度比较快的方式 之前我是用家里的玩客云绝育之后不再写盘当下载机用的&#xff0c;但是限制很多 我发现了aria2 这个下载器非常适合我&#xff0c;而有个大佬又在原来的基础…

基于 Vue3打造前台+中台通用提效解决方案(上)

基于 Vue3打造前台+中台通用提效解决方案 1、项目架构 本项目使用vite + vue3来实现前中台解决方案 2、为什么使用vite ? 因为,之前的项目一直都是使用webpack作为构建工具;vite出来这么久了,也没有用过;所以想在当前项目下进行使用; 2.1、为什么vite比webpack块? …

android开发文档下载,你的技术真的到天花板了吗

Android 基础 1.Activity 1、 什么是 Activity&#xff1f; 2、 请描述一下 Activity 生命周期 …… 2.Service 3.Broadcast Receiver32 4.ContentProvider 5.ListView 6.Intent 7.Fragment 1.Fragment 跟 Activity 之间是如何传值的 2.描述一下 Fragment 的生命周期 3.Fragme…

Qt多弹窗实现包括QDialog、QWidget、QMainWindow

1.相关说明 独立Widget窗口、嵌入式Widget、嵌入式MainWindow窗口、独立MainWindow窗口等弹窗的实现 相关界面包含关系 2.相关界面 3.相关代码 mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" #include "tformdoc.h" #incl…

容器云平台巡检实战:运维进阶技巧与策略

1 docker容器日常巡检 通过以下方式进行检查&#xff1a; 1.1 docker/podman ps查看容器状态 Docker/podman ps -a 查看容器状态STATUS&#xff1a; Exited(0)&#xff1a;表示容器正常退出 Exited(其他数字)&#xff1a;容器异常退出&#xff0c;需要通过log 查看原因 Up…

080|为什么阿里的价值观值得你关注?

在阿里巴巴20周年年会现场&#xff0c;万众瞩目之下&#xff0c;马云和张勇完成了阿里巴巴董事长职务的交接。 不过你也知道&#xff0c;这次接棒在一年前就已经公布了&#xff0c;在年会上只是一个仪式。在20周年年会过后&#xff0c;我找到了互联网圈的资深媒体人阳淼&#…

julia语言使用PyCall包调用Python代码及Python包

Julia语言虽然好&#xff0c;但是包管理方面和生态环境感觉还有一点小小的缺陷&#xff0c;但是Julia可以调用Python丰富的包&#xff0c;用起来很方便。 安装PyCall 在安装之前先确认下Julia和Python的版本&#xff0c;我使用的稳定版本的 Julia1.6.7&#xff0c;Python版本是…

电磁兼容(EMC):单、双面PCB板设计要点

目录 1 产品设计原则&#xff1a;性价比为第一要素 2 布局设计要点 3 布线设计要点 4 完整地平面不是最优方案 1 产品设计原则&#xff1a;性价比为第一要素 PCB在电磁兼容设计中通常是要求有完整的地和电源平面。但多层价格让对价格敏感的产品望而却步&#xff0c;只能采…

GPT本地化研究(JAVA版本)

1.我觉得gpt3 600多G个人是不可能部署得成功的,回想我自己个人不可能每一方面知识都知道,我只是知道最多的是我自己擅长的,百事通需要靠大公司才能解决,我们只是要关注这个gpt是哪个领域的, 我想做的是工业—>自动化gpt(貌似这个方向日本很专业了*_*) 它山之石可以攻玉 2.gp…

【设计模式 03】抽象工厂模式

一个具体的工厂&#xff0c;可以专门生产单一某一种东西&#xff0c;比如说只生产手机。但是一个品牌的手机有高端机、中端机之分&#xff0c;这些具体的属于某一档次的产品都需要单独建立一个工厂类&#xff0c;但是它们之间又彼此关联&#xff0c;因为都共同属于一个品牌。我…

视觉Transformers中的位置嵌入 - 研究与应用指南

视觉 Transformer 中位置嵌入背后的数学和代码简介。 自从 2017 年推出《Attention is All You Need》以来&#xff0c;Transformer 已成为自然语言处理 (NLP) 领域最先进的技术。 2021 年&#xff0c;An Image is Worth 16x16 Words 成功地将 Transformer 应用于计算机视觉任务…

【go语言开发】yaml文件配置和解析

本文主要介绍使用第三方库来对yaml文件配置和解析。首先安装yaml依赖库&#xff1b;然后yaml文件中配置各项值&#xff0c;并给出demo参考&#xff1b;最后解析yaml文件&#xff0c;由于yaml文件的配置在全局中可能需要&#xff0c;可定义全局变量Config&#xff0c;便于调用 文…

面试题HTML+CSS+网络+浏览器篇

文章目录 Css预处理sass less是什么&#xff1f;为什么使用他们怎么转换 less 为 css&#xff1f;重绘和回流是什么http 是什么&#xff1f;有什么特点HTTP 协议和 HTTPS 区别什么是 CSRF 攻击HTML5 新增的内容有哪些Css3 新增的特性flex VS grid清除浮动的方式有哪些&#xff…

SAR ADC学习笔记(3)

一、SAR ADC采样电路 1.采样网络的时域响应&#xff1a;采保信号 2.采样网络的KT/C噪声 3.采样抖动 采样开关的种类 1.单MOS管开关 2.传输门开关 3.栅极自举&#xff08;Bootstrap&#xff09;开关 结论&#xff1a;M4的衬底需要和B点短接&#xff0c;保证B点能够到达高压&…

完美解决Iframe嵌入帆软报表出现跨域cookie写不进去的问题

随着google chrome对第三方cookie的限制越来越狠,现在发现之前使用iframe嵌入的帆软报表已经不好使了。官方现在解决iframe嵌入帆软报表出现跨域导致cookie写不进去的方案是主推 统一主域名的方案(谷歌浏览器单点登录失败- FineReport帮助文档 - 全面的报表使用教程和学习资料…

大唐杯学习笔记:Day5

1.1 小区搜索 搜索流程 PLMN选择 自动模式&#xff1a;UE根据NAS的请求或自主地向NAS报告可用的PLMN 手动模式&#xff1a;通过手动选择一个可用的VPLMN获取正常服务 频点选择 5G NR中,3GPP主要指定了两个频率范围,一个是6GHZ以下,另一个是毫米波,分别称之为FR1和FR2。 N…

稀碎从零算法笔记Day5-LeetCode:轮转数组

题型&#xff1a;数组、数学、双指针 前言&#xff1a;LC说你得用三种方法做出来(悲) 链接&#xff1a;189. 轮转数组 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 …

专业145+总分410+西工大西北工业大学827信号与系统考研经验电子信息与通信工程,海航,真题,大纲,参考书。

经过一年的努力&#xff0c;分数终于出来。今年专业课827信号与系统145&#xff08;很遗憾差了一点点满分&#xff0c;没有达到Jenny老师的最高要求&#xff09;&#xff0c;数一130&#xff0c;英语和政治也都比较平衡&#xff0c;总分410分&#xff0c;当然和信息通信考研Jen…