Flutter(七)功能型组件

news2025/1/10 1:57:05

1.导航返回拦截(WillPopScope)

需求:再按一次退出应用
用户在1秒内点击两次返回按钮时,则退出;如果间隔超过1秒则不退出

import 'package:flutter/material.dart';

class WillPopScopeTestRoute extends StatefulWidget {
  @override
  WillPopScopeTestRouteState createState() {
    return WillPopScopeTestRouteState();
  }
}

class WillPopScopeTestRouteState extends State<WillPopScopeTestRoute> {
  DateTime? _lastPressedAt; //上次点击时间

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        if (_lastPressedAt == null ||
            DateTime.now().difference(_lastPressedAt!) > Duration(seconds: 1)) {
          //两次点击间隔超过1秒则重新计时
          _lastPressedAt = DateTime.now();
          return false;
        }
        return true;
      },
      child: Container(
        alignment: Alignment.center,
        child: Text("1秒内连续按两次返回键退出"),
      ),
    );
  }
}

2.数据共享(InheritedWidget)

InheritedWidget是 Flutter 中非常重要的一个功能型组件,它提供了一种在 widget 树中从上到下共享数据的方式,比如我们在应用的根 widget 中通过InheritedWidget共享了一个数据,那么我们便可以在任意子widget 中来获取该共享的数据!这个特性在一些需要在整个 widget 树中共享数据的场景中非常方便!如Flutter SDK中正是通过 InheritedWidget 来共享应用主题(Theme)和 Locale (当前语言环境)信息的。

3.跨组件状态共享

Provider是Flutter官方出的状态管理包
Provider (opens new window)& Scoped Model(opens new window) 这两个包都是基于InheritedWidget的,原理相似

Redux(opens new window) 是Web开发中React生态链中Redux包的Flutter实现

MobX(opens new window) 是Web开发中React生态链中MobX包的Flutter实现

BLoC(opens new window) 是BLoC模式的Flutter实现

4.颜色和主题

Theme组件可以为Material APP定义主题数据(ThemeData)。Material组件库里很多组件都使用了主题数据,如导航栏颜色、标题字体、Icon样式等。Theme内会使用InheritedWidget来为其子树共享样式数据

ThemeData({
  Brightness? brightness, //深色还是浅色
  MaterialColor? primarySwatch, //主题颜色样本,见下面介绍
  Color? primaryColor, //主色,决定导航栏颜色
  Color? cardColor, //卡片颜色
  Color? dividerColor, //分割线颜色
  ButtonThemeData buttonTheme, //按钮主题
  Color dialogBackgroundColor,//对话框背景颜色
  String fontFamily, //文字字体
  TextTheme textTheme,// 字体主题,包括标题、body等文字样式
  IconThemeData iconTheme, // Icon的默认样式
  TargetPlatform platform, //指定平台,应用特定平台控件风格
  ColorScheme? colorScheme,
  ...
})

5.按需rebuild(ValueListenableBuilder)

InheritedWidget 提供一种在 widget 树中从上到下共享数据的方式,但是也有很多场景数据流向并非从上到下,比如从下到上或者横向等。为了解决这个问题,Flutter 提供了一个 ValueListenableBuilder 组件,它的功能是监听一个数据源,如果数据源发生变化,则会重新执行其 builder

const ValueListenableBuilder({
  Key? key,
  required this.valueListenable, // 数据源,类型为ValueListenable<T>
  required this.builder, // builder
  this.child,
}

valueListenable:类型为 ValueListenable,表示一个可监听的数据源。
builder:数据源发生变化通知时,会重新调用 builder 重新 build 子组件树。
child: builder 中每次都会重新构建整个子组件树,如果子组件树中有一些不变的部分,可以传递给child,child 会作为builder的第三个参数传递给 builder,通过这种方式就可以实现组件缓存,原理和AnimatedBuilder 第三个 child 相同。

可以发现 ValueListenableBuilder 和数据流向是无关的,只要数据源发生变化它就会重新构建子组件树,因此可以实现任意流向的数据共享。

6.异步UI更新(FutureBuilder、StreamBuilder)

在实际开发中依赖异步数据更新UI的这种场景非常常见,因此Flutter专门提供了FutureBuilder和StreamBuilder两个组件来快速实现这种功能

FutureBuilder

FutureBuilder({
  this.future,//FutureBuilder依赖的Future,通常是一个异步耗时任务。
  this.initialData,//初始数据,用户设置默认数据。
  required this.builder,//Widget构建器;该构建器会在Future执行的不同阶段被多次调用
})

builder构建

Function (BuildContext context, AsyncSnapshot snapshot) 

snapshot会包含当前异步任务的状态信息及结果信息 ,比如我们可以通过snapshot.connectionState获取异步任务的状态信息、通过snapshot.hasError判断异步任务是否有错误等等,完整的定义读者可以查看AsyncSnapshot类定义。

另外,FutureBuilder的builder函数签名和StreamBuilder的builder是相同的

示例:
从网上获取数据,获取数据时弹一个加载框;获取结束时,如果成功则显示获取到的数据,如果失败则显示错误

Future<String> mockNetworkData() async {
  return Future.delayed(Duration(seconds: 2), () => "我是从互联网上获取的数据");
}
Widget build(BuildContext context) {
  return Center(
    child: FutureBuilder<String>(
      future: mockNetworkData(),
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        // 请求已结束
        if (snapshot.connectionState == ConnectionState.done) {
          if (snapshot.hasError) {
            // 请求失败,显示错误
            return Text("Error: ${snapshot.error}");
          } else {
            // 请求成功,显示数据
            return Text("Contents: ${snapshot.data}");
          }
        } else {
          // 请求未结束,显示loading
          return CircularProgressIndicator();
        }
      },
    ),
  );
}

每次组件重新build 都会重新发起请求,因为每次的 future 都是新的,
可以加缓存,future 成功后将 future 缓存,这样下次build时,就不会再重新发起异步任务

StreamBuilder

和Future 不同的是,它可以接收多个异步操作的结果,它常用于会多次读取数据的异步任务场景,如网络内容下载、文件读写等

StreamBuilder({
  this.initialData,
  Stream<T> stream,
  required this.builder,
}) 

和FutureBuilder的构造函数只有一点不同:前者需要一个future,而后者需要一个stream。

计时器的示例

Stream<int> counter() {
  return Stream.periodic(Duration(seconds: 1), (i) {
    return i;
  });
}
 Widget build(BuildContext context) {
    return StreamBuilder<int>(
      stream: counter(), //
      //initialData: ,// a Stream<int> or null
      builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
        if (snapshot.hasError)
          return Text('Error: ${snapshot.error}');
        switch (snapshot.connectionState) {
          case ConnectionState.none:
            return Text('没有Stream');
          case ConnectionState.waiting:
            return Text('等待数据...');
          case ConnectionState.active:
            return Text('active: ${snapshot.data}');
          case ConnectionState.done:
            return Text('Stream 已关闭');
        }
        return null; // unreachable
      },
    );
 }

7.对话框详解

AlertDialog

const AlertDialog({
  Key? key,
  this.title, //对话框标题组件
  this.titlePadding, // 标题填充
  this.titleTextStyle, //标题文本样式
  this.content, // 对话框内容组件
  this.contentPadding = const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0), //内容的填充
  this.contentTextStyle,// 内容文本样式
  this.actions, // 对话框操作按钮组
  this.backgroundColor, // 对话框背景色
  this.elevation,// 对话框的阴影
  this.semanticLabel, //对话框语义化标签(用于读屏软件)
  this.shape, // 对话框外形
})

使用

AlertDialog(
  title: Text("提示"),
  content: Text("您确定要删除当前文件吗?"),
  actions: <Widget>[
    TextButton(
      child: Text("取消"),
      onPressed: () => Navigator.of(context).pop(), //关闭对话框
    ),
    TextButton(
      child: Text("删除"),
      onPressed: () {
        // ... 执行删除操作
        Navigator.of(context).pop(true); //关闭对话框
      },
    ),
  ],
);

弹出:

Future<T?> showDialog<T>({
  required BuildContext context,
  required WidgetBuilder builder, // 对话框UI的builder
  bool barrierDismissible = true, //点击对话框barrier(遮罩)时是否关闭它
})

示例

点击对话框“取消”按钮或遮罩,控制台就会输出"取消删除",如果点击“删除”按钮,控制台就会输出"已确认删除"。

//点击该按钮后弹出对话框
ElevatedButton(
  child: Text("对话框1"),
  onPressed: () async {
    //弹出对话框并等待其关闭
    bool? delete = await showDeleteConfirmDialog1();
    if (delete == null) {
      print("取消删除");
    } else {
      print("已确认删除");
      //... 删除文件
    }
  },
),

// 弹出对话框
Future<bool?> showDeleteConfirmDialog1() {
  return showDialog<bool>(
    context: context,
    builder: (context) {
      return AlertDialog(
        title: Text("提示"),
        content: Text("您确定要删除当前文件吗?"),
        actions: <Widget>[
          TextButton(
            child: Text("取消"),
            onPressed: () => Navigator.of(context).pop(), // 关闭对话框
          ),
          TextButton(
            child: Text("删除"),
            onPressed: () {
              //关闭对话框并返回true
              Navigator.of(context).pop(true);
            },
          ),
        ],
      );
    },
  );
}

SimpleDialog也是Material组件库提供的对话框

Future<void> changeLanguage() async {
  int? i = await showDialog<int>(
      context: context,
      builder: (BuildContext context) {
        return SimpleDialog(
          title: const Text('请选择语言'),
          children: <Widget>[
            SimpleDialogOption(
              onPressed: () {
                // 返回1
                Navigator.pop(context, 1);
              },
              child: Padding(
                padding: const EdgeInsets.symmetric(vertical: 6),
                child: const Text('中文简体'),
              ),
            ),
            SimpleDialogOption(
              onPressed: () {
                // 返回2
                Navigator.pop(context, 2);
              },
              child: Padding(
                padding: const EdgeInsets.symmetric(vertical: 6),
                child: const Text('美国英语'),
              ),
            ),
          ],
        );
      });

  if (i != null) {
    print("选择了:${i == 1 ? "中文简体" : "美国英语"}");
  }
}

AlertDialog和SimpleDialog都使用了Dialog类。
AlertDialog和SimpleDialog中使用了IntrinsicWidth来尝试通过子组件的实际尺寸来调整自身尺寸,
这就导致他们的子组件不能是延迟加载模型的组件(如ListView、GridView 、 CustomScrollView

如果需要嵌套一个ListView可以直接使用Dialog类

Dialog(
  child: ListView(
    children: ...//省略
  ),
);
Future<void> showListDialog() async {
  int? index = await showDialog<int>(
    context: context,
    builder: (BuildContext context) {
      var child = Column(
        children: <Widget>[
          ListTile(title: Text("请选择")),
          Expanded(
              child: ListView.builder(
            itemCount: 30,
            itemBuilder: (BuildContext context, int index) {
              return ListTile(
                title: Text("$index"),
                onTap: () => Navigator.of(context).pop(index),
              );
            },
          )),
        ],
      );
      //使用AlertDialog会报错
      //return AlertDialog(content: child);
      return Dialog(child: child);
    },
  );
  if (index != null) {
    print("点击了:$index");
  }
}

对话框打开动画及遮罩

封装一个showCustomDialog方法,它定制的对话框动画为缩放动画,并同时制定遮罩颜色为Colors.black87

Future<T?> showCustomDialog<T>({
  required BuildContext context,
  bool barrierDismissible = true,
  required WidgetBuilder builder,
  ThemeData? theme,
}) {
  final ThemeData theme = Theme.of(context, shadowThemeOnly: true);
  return showGeneralDialog(
    context: context,
    pageBuilder: (BuildContext buildContext, Animation<double> animation,
        Animation<double> secondaryAnimation) {
      final Widget pageChild = Builder(builder: builder);
      return SafeArea(
        child: Builder(builder: (BuildContext context) {
          return theme != null
              ? Theme(data: theme, child: pageChild)
              : pageChild;
        }),
      );
    },
    barrierDismissible: barrierDismissible,
    barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
    barrierColor: Colors.black87, // 自定义遮罩颜色
    transitionDuration: const Duration(milliseconds: 150),
    transitionBuilder: _buildMaterialDialogTransitions,
  );
}

Widget _buildMaterialDialogTransitions(
    BuildContext context,
    Animation<double> animation,
    Animation<double> secondaryAnimation,
    Widget child) {
  // 使用缩放动画
  return ScaleTransition(
    scale: CurvedAnimation(
      parent: animation,
      curve: Curves.easeOut,
    ),
    child: child,
  );
}

遮罩颜色比通过showDialog方法打开的对话框更深。另外对话框打开/关闭的动画已变为缩放动画了

对话框状态管理

在这里插入图片描述

要更新UI只需改变状态后通知框架页面需要重构即可,而Element的markNeedsBuild()方法正是来实现这个功能的
在组件树中,context实际上就是Element对象的引用

Future<bool?> showDeleteConfirmDialog4() {
  bool _withTree = false;
  return showDialog<bool>(
    context: context,
    builder: (context) {
      return AlertDialog(
        title: Text("提示"),
        content: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            Text("您确定要删除当前文件吗?"),
            Row(
              children: <Widget>[
                Text("同时删除子目录?"),
                Checkbox( // 依然使用Checkbox组件
                  value: _withTree,
                  onChanged: (bool value) {
                    // 此时context为对话框UI的根Element,我们 
                    // 直接将对话框UI对应的Element标记为dirty
                    (context as Element).markNeedsBuild();
                    _withTree = !_withTree;
                  },
                ),
              ],
            ),
          ],
        ),
        actions: <Widget>[
          TextButton(
            child: Text("取消"),
            onPressed: () => Navigator.of(context).pop(),
          ),
          TextButton(
            child: Text("删除"),
            onPressed: () {
              // 执行删除操作
              Navigator.of(context).pop(_withTree);
            },
          ),
        ],
      );
    },
  );
}

我们只需要更新复选框的状态,而此时的context我们用的是对话框的根context,所以会导致整个对话框UI组件全部rebuild,因此最好的做法是将context的“范围”缩小,也就是说只将Checkbox的Element标记为dirty,优化后的代码为:

Row(
  children: <Widget>[
    Text("同时删除子目录?"),
    // 通过Builder来获得构建Checkbox的`context`,
    // 这是一种常用的缩小`context`范围的方式
    Builder(
      builder: (BuildContext context) {
        return Checkbox(
          value: _withTree,
          onChanged: (bool value) {
            (context as Element).markNeedsBuild();
            _withTree = !_withTree;
          },
        );
      },
    ),
  ],
),

其他对话框

底部菜单列表

// 弹出底部菜单列表模态对话框
Future<int?> _showModalBottomSheet() {
  return showModalBottomSheet<int>(
    context: context,
    builder: (BuildContext context) {
      return ListView.builder(
        itemCount: 30,
        itemBuilder: (BuildContext context, int index) {
          return ListTile(
            title: Text("$index"),
            onTap: () => Navigator.of(context).pop(index),
          );
        },
      );
    },
  );
}

Loading框

showLoadingDialog() {
  showDialog(
    context: context,
    barrierDismissible: false, //点击遮罩不关闭对话框
    builder: (context) {
      return AlertDialog(
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            CircularProgressIndicator(),
            Padding(
              padding: const EdgeInsets.only(top: 26.0),
              child: Text("正在加载,请稍后..."),
            )
          ],
        ),
      );
    },
  );
}

Loading框得宽度可以使用UnconstrainedBox先抵消showDialog对宽度的约束,然后再使用SizedBox指定宽度

UnconstrainedBox(
  constrainedAxis: Axis.vertical,
  child: SizedBox(
    width: 280,
    child: AlertDialog(
      content: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          CircularProgressIndicator(value: .8,),
          Padding(
            padding: const EdgeInsets.only(top: 26.0),
            child: Text("正在加载,请稍后..."),
          )
        ],
      ),
    ),
  ),
);

日历

Future<DateTime?> _showDatePicker1() {
  var date = DateTime.now();
  return showDatePicker(
    context: context,
    initialDate: date,
    firstDate: date,
    lastDate: date.add( //未来30天可选
      Duration(days: 30),
    ),
  );
}

iOS风格的日历选择器需要使用showCupertinoModalPopup方法和CupertinoDatePicker组件来实现

Future<DateTime?> _showDatePicker2() {
  var date = DateTime.now();
  return showCupertinoModalPopup(
    context: context,
    builder: (ctx) {
      return SizedBox(
        height: 200,
        child: CupertinoDatePicker(
          mode: CupertinoDatePickerMode.dateAndTime,
          minimumDate: date,
          maximumDate: date.add(
            Duration(days: 30),
          ),
          maximumYear: date.year + 1,
          onDateTimeChanged: (DateTime value) {
            print(value);
          },
        ),
      );
    },
  );
}

完。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

建筑行业数字化转型,工程管理系统已成建筑行业转型的利器

建筑工程项目管理的困境 专业工种多、工作环境复杂&#xff0c;工期长&#xff0c;且整体工业化标准化程度较低。 进度难管控、项目沟通协作不畅、项目执行过程不透明、项目成本管控难、项目盈亏情况不清、项目难共享等。 什么是工程项目管理 工程项目管理指的是对工程项目…

茶润童心 以茶明礼

中国是茶的故乡&#xff0c;也是茶文化的发源地&#xff0c;茶文化也是中国文化的一部分。5月27日下午&#xff0c;8位武汉公益小天使来到中茶恩施硒茶全国运营中心开展少儿茶艺活动。 开场的自我介绍&#xff0c;公益小天使逐个进行自我介绍&#xff0c;喊着“好名字”互相加…

软件测试的一些关键点

软件测试的一些关键点 随着互联网的快速发展&#xff0c;软件已经成为了我们生活和工作中不可或缺的一部分。在软件开发过程中&#xff0c;一项重要的工作就是软件测试。软件测试是指对软件产品或系统进行验证和验证的过程。在软件测试中&#xff0c;需要注意以下关键点。 首先…

[转]Github进行fork后如何与原仓库同步

问题场景&#xff1a; 新公司要求所有的代码提交都要先通过自己的库提交到主repo上去&#xff0c;所以先在gitlab网页上fork出一个自己的库&#xff0c;在本地修改完代码后提交到远程自己库上&#xff0c;然后在gitlab网页上发起一个merge request请求&#xff0c;然后等待主r…

面试:webpack常用loader和plugin

Webpack简介 Webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时&#xff0c;它会在内部从一个或多个入口点构建一个 依赖图(dependency graph)&#xff0c;然后将你项目中所需的每一个模块组合成一个或多个 bundles&#xff0c;它们均…

如何选择专业的低代码开发平台?为企业数字化转型保驾护航

在当今快节奏的商业环境中&#xff0c;软件开发已经成为任何组织的关键方面。然而&#xff0c;由于市场上有无数的软件开发平台&#xff0c;选择合适的平台可能是一项艰巨的任务。对于任何想要创建满足其业务需求的高质量应用程序的组织来说&#xff0c;选择正确的软件开发平台…

英国卡迪夫大学学生使用ChatGPT写论文拿到一等成绩

近日&#xff0c;BBC报道了一则新闻&#xff1a; 卡迪夫大学一名学生在期末考试中使用ChatGPT撰写了一篇论文&#xff0c;并获得了一等成绩&#xff0c;要知道这是英国大学中最高等级的成绩&#xff0c;而他的另一篇论文没有使用ChatGPT&#xff0c;只获得了二等一的成绩。 此…

1.6. 数组

数组是一种数据结构&#xff0c;用于存储相同类型的多个元素。在 Java 中&#xff0c;数组是一个对象&#xff0c;它具有一定数量的连续内存空间。数组中的每个元素都有一个索引&#xff0c;用于访问和操作元素。 1.6.1. 数组的声明与初始化 在 Java 中&#xff0c;可以使用以…

Find My资讯|iOS17将重点改进钱包、Find My、SharePlay和AirPlay等功能

彭博社的马克・古尔曼&#xff08;Mark Gurman&#xff09;在最新一期 Power On 时事通讯中表示&#xff0c;苹果即将推出的 iOS 17 系统将改进 Wallet、Find My、SharePlay 和 AirPlay 等多项功能。 古尔曼在博文中还表示苹果会增强 Find My 的位置服务&#xff0c;同样也没…

前端数据可视化开发平台FlyFish数据源应用教程详解

介绍 飞鱼&#xff08;FlyFish&#xff09;是云智慧开源的一款免费的数据可视化编排平台。通过简易的方式快速创建数据模型&#xff0c;通过拖拉拽的形式&#xff0c;快速生成一套数据可视化解决方案。在飞鱼产品中可以通过直接连接 MySQL 、 Oracle 等数据库直接从数据源中获…

LiangGaRy-学习笔记-Day17

1、磁盘的介绍 自动分区、手工分区、命令工具分区 1.1、磁盘分类 根据介质来区分&#xff1a; 机械硬盘和固态硬盘 通过盘大小&#xff1a; 3.5英寸和2.5英寸 通过接口分类&#xff1a; SAS、SATA、FC scisi 根据功能&#xff1a; 桌面和企业级别 1.2、磁盘类型 HD…

关于【Stable-Diffusion WEBUI】生成全身图:插件解决面部崩坏问题

文章目录 &#xff08;零&#xff09;前言&#xff08;一&#xff09;脸难看的问题&#xff08;1.1&#xff09;面部修复&#xff08;1.2&#xff09;远景脸部问题 &#xff08;二&#xff09;面部修复插件&#xff08;Face Editor&#xff09;&#xff08;2.1&#xff09;模型…

最常见JS加密保护代码的方法

当谈到JavaScript&#xff08;简称JS&#xff09;代码的保护时&#xff0c;加密是一种常见的策略。加密可以帮助保护你的JS代码&#xff0c;防止未经授权的访问、修改和复制。在本文中&#xff0c;我将向你介绍一些常用的js加密保护方法&#xff0c;并提供一些通俗易懂的示例代…

如何有效和快速清理C盘

电脑在运行过程中会产生磁盘碎片&#xff0c;时间一长垃圾文件就会越多。而且我们平常不敢乱清理C盘中的文件&#xff0c;以免因为误删导致系统出现故障&#xff0c;所以垃圾文件才肆意占用系统盘空间。不过我们可以选择系统自带的“磁盘清理”功能“制服”它&#xff0c;给C盘…

(转载)多种群遗传算法的函数优化算法

以下内容大部分来源于《MATLAB智能算法30个案例分析》&#xff0c;仅为学习交流所用。 1 理论基础 1.1 遗传算法早熟问题 遗传算法是一种借鉴生物界自然选择和进化机制发展起来的高度并行、随机、自适应的全局优化概率搜索算法。由于优化时不依赖于梯度&#xff0c;具有很强…

商代数与积代数

商代数 设 R R R使 A < S , ∗ 1 , ∗ 2 , ⋯ , ∗ n > A \left<S, *_1, *_2,\cdots, *_n\right> A⟨S,∗1​,∗2​,⋯,∗n​⟩上的同余关系&#xff0c;则 R R R使 S S S上的等价关系&#xff0c;因此 R R R可诱导出 S S S的一个划分 S / R { [ a ] R ∣ a ∈…

【大数据处理与可视化】七、时间序列分析

【大数据处理与可视化】七、时间序列分析 实验目的实验内容实验步骤一、案例——股票收盘价分析1、读取数据&#xff0c;并转换成DataFrame对象展示2、将“交易日期”一列设置为行索引3、根据数据中“收盘价”一列的数据绘制一张折线图&#xff0c;以了解近些年来收盘价格的趋势…

Buck环路响应伯德图Mathcad绘制

一直不理解环路响应&#xff0c;调试也是应用参考电路&#xff0c;虽然自动化的课程忘的差不多了&#xff0c;但也不是偷懒的借口&#xff0c;直到昨天看到可以用Mathcad计算BUCK电路工作在电压控制的CCM连续模式&#xff0c;这是基于开关平均法推导出的小信号传递函数模型。原…

IDEA-报错 Failed to read artifact descriptor for xxx解决方法

项目场景&#xff1a; idea下载若依微服务的项目&#xff0c;配置环境产生了报错 问题描述 在idea里配置环境时maven报错Failed to read artifact descriptor for xxxx 原因分析&#xff1a; 在进行导包的时候maven和jdk版本导致的&#xff0c;更换版本之后大部分报错不存在…

分享一个科幻风的404

先看效果&#xff1a; 再看代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>404页面</title><script src"https://cdnjs.cloudflare.com/ajax/libs/three.js/r125/th…