当前位置: 首页 > news >正文

flutter学习-day12-可滚动组件和监听

📚 目录

  1. 简介
  2. 可滚动组件
    1. SingleChildScrollView
    2. ListView
      1. separated分割线
      2. 无限加载列表
      3. 带标题列表
  3. 滚动监听和控制
    1. ScrollController滚动监听
    2. NotificationListener滚动监听
  4. AnimatedList动画列表
  5. 滚动网格布局GridView
    1. 横轴子元素为固定数量
    2. 横轴子元素为固定最大长度
    3. 动态创建
  6. PageView页面切换和缓存
    1. PageState缓存
  7. TabBarView
  8. CustomScrollView和Slivers
    1. 常用的Slivers

本文学习和引用自《Flutter实战·第二版》:作者:杜文

1. 简介

通常可滚动组件的子组件可能会非常多、占用的总高度也会非常大;如果要一次性将子组件全部构建出将会非常昂贵!为此,Flutter中提出一个Sliver(中文为“薄片”的意思)概念,Sliver 可以包含一个或多个子组件。Sliver 的主要作用是配合:加载子组件并确定每一个子组件的布局和绘制信息,如果 Sliver 可以包含多个子组件时,通常会实现按需加载模型。只有当 Sliver 出现在视口中时才会去构建它,这种模型也称为“基于Sliver的列表按需加载模型”。可滚动组件中有很多都支持基于Sliver的按需加载模型,如ListView、GridView,但是也有不支持该模型的,如SingleChildScrollView。

Flutter 中的可滚动组件主要由三个角色组成:

  • Scrollable :用于处理滑动手势,确定滑动偏移,滑动偏移变化时构建 Viewport。
方法描述
axisDirection-滚动方向
physicsClampingScrollPhysics、BouncingScrollPhysics决定可滚动组件如何响应用户操作
controller-控制滚动位置和监听滚动事件
viewportBuilder-当用户滑动时,Scrollable 会调用此回调构建新的 Viewport,同时传递一个 ViewportOffset 类型的 offset 参数,该参数描述 Viewport 应该显示那一部分内容
  • Viewport:显示的视窗,即列表的可视区域。
方法描述
axisDirection-滚动方向
offset-用户的滚动偏移
cacheExtent-预渲染区域
CacheExtentStyle-用于配合解释cacheExtent的含义,也可以为主轴长度的乘数
slivers-需要显示的 Sliver 列表
  • Sliver:视窗里显示的元素,对子组件进行构建和布局。

如果要给可滚动组件添加滚动条,只需将Scrollbar作为可滚动组件的任意一个父级组件即可

2. 可滚动组件

本节讲一下SingleChildScrollView和ListView。

2-1 SingleChildScrollView

SingleChildScrollView类似于Android中的ScrollView,它只能接收一个子组件。通常SingleChildScrollView只应在期望的内容不会超过屏幕太多时使用,因为不支持基于 Sliver 的延迟加载模型,可能性能差。

方法描述
scrollDirection-滚动方向
reverse-
padding-内边距
primary-是否使用 widget 树中默认的PrimaryScrollControlle
physics-决定可滚动组件如何响应用户操作
controller-控制器
child-子组件

竖向排列的字母表例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {String alphabet = 'ABCDEFGHIJKMLNOPKRSTUVWSYZ';Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Scrollbar(child: SingleChildScrollView(padding: const EdgeInsets.all(16.0),child: Center(child: Column(children: alphabet.split('').map((e) => Text(e,textScaleFactor: 2.0,)).toList(),)),),));}
}

2-2. ListView

ListView是最常用的可滚动组件之一,内部组合了 Scrollable、Viewport 和 Sliver。它可以沿一个方向线性排布所有子组件,并且它也支持列表项懒加载(在需要时才会创建)。它有一个children参数,它接受一个Widget列表。这种方式适合只有少量的子组件数量已知且比较少的情况,反之则应该使用ListView.builder 按需动态构建列表项。

方法描述
itemExtent-子组件长度,如果指定了该值,就不用动态计算listview高度,性能更好
prototypeItem-指定一个列表项,可滚动组件会在 layout 时计算一次它延主轴方向的长度,和itemExtent互斥
shrinkWrapfalse是否根据子组件的总长度来设置ListView的长度
addRepaintBoundaries-是否将列表项(子组件)包裹在RepaintBoundary组件中,看list复杂情况设置
  • 数量固定的情况:
ListView(shrinkWrap: true, padding: const EdgeInsets.all(16.0),children: <Widget>[const Text('a'),const Text('b'),const Text('c'),const Text('d'),],
);
  • 数量不固定的情况:
ListView.builder(itemCount: 100,// 强制高度为50.0itemExtent: 50.0,itemBuilder: (BuildContext context, int index) {return ListTile(title: Text("$index"));}
);

2-2-1. separated分割线

ListView.separated可以在生成的列表项之间添加一个分割组件,它比ListView.builder多了一个separatorBuilder参数,该参数是一个分割组件生成器。

  • 奇数行添加一条红色下划线,偶数行添加一条绿色下划线:
import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {Widget divider1 = const Divider(color: Colors.red);Widget divider2 = const Divider(color: Colors.green);Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: ListView.separated(itemCount: 100,// 列表项构造器itemBuilder: (BuildContext context, int index) {return ListTile(title: Text("$index"));},// 分割器构造器separatorBuilder: (BuildContext context, int index) {return index % 2 == 0 ? divider1 : divider2;},));}
}

2-2-2. 无限加载列表

在实际开发中,我们经常需要实现一个无限加载列表,即当列表滚动到底部时,再向服务器请求数据,并添加到列表,例子如下:

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {static const loadingTag = "##loading##"; //表尾标记var words = <String>[loadingTag];void initState() {super.initState();_retrieveData();}// 加载数据void _retrieveData() {Future.delayed(const Duration(seconds: 2)).then((e) {setState(() {//重新构建列表words.insertAll(words.length - 1,//每次生成20个单词generateWordPairs().take(20).map((e) => e.asPascalCase).toList(),);});});}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: ListView.separated(itemCount: words.length,itemBuilder: (context, index) {// 如果到了表尾if (words[index] == loadingTag) {// 不足100条,继续获取数据if (words.length - 1 < 100) {// 获取数据_retrieveData();// 加载时显示loadingreturn Container(padding: const EdgeInsets.all(16.0),alignment: Alignment.center,child: const SizedBox(width: 24.0,height: 24.0,child: CircularProgressIndicator(strokeWidth: 2.0),),);} else {// 已经加载了100条数据,不再获取数据return Container(alignment: Alignment.center,padding: const EdgeInsets.all(16.0),child: const Text("没有更多了",style: TextStyle(color: Colors.grey),),);}}// 显示单词列表项return ListTile(title: Text(words[index]));},separatorBuilder: (context, index) => const Divider(height: .0),));}
}

2-2-3. 带标题列表

Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Column(children: [// 标题const ListTile(title: Text('标题')),// 用Expanded 占满剩余空间Expanded(child: ListView.builder(itemBuilder: (BuildContext context, int index) {return ListTile(title: Text('行:$index'),);}),)],));}

3. 滚动监听和控制

可以用ScrollController来控制可滚动组件的滚动位置。而,可滚动组件在滚动时会发送ScrollNotification类型的通知,ScrollBar正是通过监听滚动通知来实现的。

3-1. ScrollController滚动监听

ScrollController间接继承自Listenable,我们可以根据ScrollController来监听滚动事件。如下例子:

  • 滚动到1000的时候,出现回到顶部的按钮,点击即可回到顶部
import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {/// 监听控制器ScrollController myController = ScrollController();/// 是否显示回到顶部按钮bool toTop = false;void initState() {super.initState();/// 开启监听myController.addListener(() {if (myController.offset < 1000 && toTop) {setState(() {toTop = false;});} else if (myController.offset >= 1000 && toTop == false) {setState(() {toTop = true;});}});}void dispose() {/// 注销监听myController.dispose();super.dispose();}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Scrollbar(child: ListView.builder(/// 固定列数itemCount: 100,/// 固定列高itemExtent: 50.0,controller: myController,/// 渲染行itemBuilder: (BuildContext context, int index) {return ListTile(title: Text('行:$index'));},)),/// 返回顶部按钮floatingActionButton: !toTop? null: FloatingActionButton(child: const Icon(Icons.arrow_upward),onPressed: () {/// 动画返回myController.animateTo(0.0,duration: const Duration(microseconds: 200),curve: Curves.ease);},),);}
}

3-2. NotificationListener滚动监听

和ScrollController不同,NotificationListener可以在可滚动组件到widget树根之间任意位置监听,而ScrollController只能和具体的可滚动组件关联后才可以。并且,收到滚动事件时,NotificationListener通知中会携带当前滚动位置和ViewPort的一些信息,而ScrollController只能获取当前滚动位置。如下例子:

  • 中间有个文字会显示滚动的进度是多少
import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {/// 进度文案String myProgress = '0%';Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: NotificationListener(onNotification: (ScrollNotification  notification) {double progress = notification.metrics.pixels / notification.metrics.maxScrollExtent;setState(() {myProgress = '${(progress * 100).toInt()}%';});return false;},child: Stack(alignment: Alignment.center,children: [ListView.builder(itemCount: 100,itemExtent: 50.0,itemBuilder: (context, index) => ListTile(title: Text('第$index行'),),),CircleAvatar(radius: 30.0,backgroundColor: Colors.black12,child: Text(myProgress))],),));}
}

4. AnimatedList动画列表

AnimatedList 和 ListView 的功能大体相似,不同的是, AnimatedList 可以在列表中插入或删除节点时执行一个动画,在需要添加或删除列表项的场景中会提高用户体验。如下例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {/// 数据列表var dataList = <String>[];/// 初始个数int counter = 6;/// Keyfinal myKey = GlobalKey<AnimatedListState>();void initState() {super.initState();/// 初始化数据for (var i = 0; i < counter; i++) {dataList.add('标题:${i + 1}');}}Widget buildItem(context, index) {String str = dataList[index];return ListTile(key: ValueKey(str),title: Text(str),trailing: IconButton(icon: const Icon(Icons.delete),onPressed: () {/// 删除的逻辑和动画setState(() {myKey.currentState!.removeItem(index, (context, animation) {var item = buildItem(context, index);dataList.removeAt(index);return FadeTransition(opacity: CurvedAnimation(parent: animation, curve: const Interval(0.5, 1.0)),child: SizeTransition(sizeFactor: animation,axisAlignment: 0.0,child: item,),);}, duration: const Duration(milliseconds: 200));});},),);}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Stack(alignment: Alignment.center,children: [AnimatedList(key: myKey,initialItemCount: dataList.length,itemBuilder: (context, index, animation) {return FadeTransition(opacity: animation, child: buildItem(context, index));},),Positioned(left: 0,right: 0,bottom: 30.0,child: FloatingActionButton(/// 添加项onPressed: () {dataList.add('标题:${++counter}');myKey.currentState!.insertItem(dataList.length - 1);},child: const Icon(Icons.add),),)],));}
}

5. 滚动网格布局GridView

GridView是ListView的升级版,可以构建二维网格列表,可以指定子组件的布局方式,如网格布局、列表布局等。他的参数和ListView是一致的,唯一区别是多了个gridDelegate参数,控制GridView子组件的排列。它提供了SliverGridDelegateWithFixedCrossAxisCount和SliverGridDelegateWithMaxCrossAxisExtent两个子类。

5-1. 横轴子元素为固定数量

使用SliverGridDelegateWithFixedCrossAxisCount,可以实现一个横轴为固定数量子元素的layout布局。子元素的大小(最大显示空间)是通过crossAxisCount和childAspectRatio两个参数共同决定的。

/// 写法一
GridView(gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(/// 横轴子元素的数量crossAxisCount: 3,/// 主轴方向的间距mainAxisSpacing: 10.0,/// 横轴方向子元素的间距crossAxisSpacing: 20.0,/// 子元素在横轴长度和主轴长度的比例childAspectRatio: 1.0),/// 元素列表children: const [Icon(Icons.ac_unit),Icon(Icons.airport_shuttle),Icon(Icons.all_inclusive),Icon(Icons.beach_access),Icon(Icons.cake),Icon(Icons.free_breakfast)]
)
/// 写法二
GridView.count( crossAxisCount: 3,childAspectRatio: 1.0,children: const [Icon(Icons.ac_unit),Icon(Icons.airport_shuttle),Icon(Icons.all_inclusive),Icon(Icons.beach_access),Icon(Icons.cake),Icon(Icons.free_breakfast),],
)

5-2. 横轴子元素为固定最大长度

使用SliverGridDelegateWithMaxCrossAxisExtent,可以实现一个横轴子元素为固定最大长度的layout布局,子元素的大小(最大显示空间)是通过maxCrossAxisExtent参数决定的。

/// 写法一
GridView(gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(/// 子元素在横轴上的最大长度maxCrossAxisExtent: 100.0,/// 子元素在横轴长度和主轴长度的比例childAspectRatio: 1.0,/// 主轴方向的间距mainAxisSpacing: 10.0,/// 横轴方向子元素的间距crossAxisSpacing: 20.0,),children: const [Icon(Icons.ac_unit),Icon(Icons.airport_shuttle),Icon(Icons.all_inclusive),Icon(Icons.beach_access),Icon(Icons.cake),Icon(Icons.free_breakfast)]
)/// 写法二
GridView.extent(maxCrossAxisExtent: 120.0,childAspectRatio: 1.0,children: const [Icon(Icons.ac_unit),Icon(Icons.airport_shuttle),Icon(Icons.all_inclusive),Icon(Icons.beach_access),Icon(Icons.cake),Icon(Icons.free_breakfast),],
)

5-3. 动态创建

当子widget比较多时,我们可以通过GridView.builder来动态创建子widget。如下例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {/// Icon列表List<IconData> myIcons = [];void initState() {super.initState();/// 初始化数据handleSyncAddIcon();}/// 模拟异步获取数据void handleSyncAddIcon() {Future.delayed(const Duration(milliseconds: 2000)).then((e) {setState(() {myIcons.addAll([Icons.ac_unit,Icons.airport_shuttle,Icons.all_inclusive,Icons.beach_access,Icons.cake,Icons.free_breakfast,]);});});}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: GridView.builder(gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(/// 每行三列crossAxisCount: 3,/// 显示区域宽高相等childAspectRatio: 1.0,),itemCount: myIcons.length,itemBuilder: (context, index) {/// 如果显示到最后一个 并且Icon总数小于200时 继续获取数据if (index == myIcons.length - 1 && myIcons.length < 200) {handleSyncAddIcon();}return Icon(myIcons[index]);},));}
}

6. PageView页面切换和缓存

如果要实现页面切换和 Tab 布局,Tab 换页效果、图片轮动以及抖音上下滑页切换视频功能等等,我们可以使用 PageView 组件。如下全屏切换的例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class PageItem extends StatefulWidget {const PageItem({Key? key,required this.text}) : super(key: key);final String text;PageItemState createState() => PageItemState();
}class PageItemState extends State<PageItem> {Widget build(BuildContext context) {debugPrint('触发${widget.text}');return Center(child: Text("第${widget.text}页", textScaleFactor: 5));}
}class HomePageState extends State<HomePage> {var children = <Widget>[];void initState() {super.initState();for (int i = 0; i < 6; ++i) {children.add(PageItem(text: '$i'));}}Widget build(BuildContext context) {debugPrint('触发');return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: PageView(/// 每次滑动是否强制切换整个页面pageSnapping: true,padEnds: true,/// 滑动方向scrollDirection: Axis.vertical,/// 子元素children: children,));}
}

6-1. PageState缓存

只需要让 PageState 混入这个 AutomaticKeepAliveClientMixin ,简单改造就可以实现缓存。

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class PageItem extends StatefulWidget {const PageItem({Key? key,required this.text}) : super(key: key);final String text;PageItemState createState() => PageItemState();
}class PageItemState extends State<PageItem> with AutomaticKeepAliveClientMixin {Widget build(BuildContext context) {super.build(context);debugPrint('触发${widget.text}');return Center(child: Text("第${widget.text}页", textScaleFactor: 5));}/// 是否需要缓存bool get wantKeepAlive => true;
}class HomePageState extends State<HomePage> {var children = <Widget>[];void initState() {super.initState();for (int i = 0; i < 6; ++i) {children.add(PageItem(text: '$i'));}}Widget build(BuildContext context) {debugPrint('触发');return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: PageView(/// 每次滑动是否强制切换整个页面pageSnapping: true,padEnds: true,/// 滑动方向scrollDirection: Axis.vertical,/// 子元素children: children,));}
}

7. TabBarView

abBarView 封装了 PageView,而abController 用于监听和控制 TabBarView 的页面切换,通常和 TabBar 联动。如果没有指定,则会在组件树中向上查找并使用最近的一个 DefaultTabController。如下例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class PageItem extends StatefulWidget {const PageItem({Key? key, required this.text}) : super(key: key);final String text;PageItemState createState() => PageItemState();
}class PageItemState extends State<PageItem> with AutomaticKeepAliveClientMixin {Widget build(BuildContext context) {super.build(context);debugPrint('触发${widget.text}');return Center(child: Text("${widget.text}", textScaleFactor: 5));}/// 是否需要缓存bool get wantKeepAlive => true;
}class HomePageState extends State<HomePage> {var children = <Widget>[];List tabs = ["新闻", "历史", "图片"];void initState() {super.initState();for (int i = 0; i < tabs.length; ++i) {children.add(PageItem(text: '${tabs[i]}'));}}Widget build(BuildContext context) {return DefaultTabController(length: children.length,child: Scaffold(appBar: AppBar(title: const Text("App Name"),bottom: TabBar(tabs: tabs.map((e) => Tab(text: e)).toList(),),),body: TabBarView(/// tab子页面children: children,),),);}
}

8. CustomScrollView和Slivers

CustomScrollView的 slivers 参数接受一个 Sliver 数组,这样就可以在一个页面中,同时包含多个可滚动组件,且使它们的滑动效果能统一起来。如下例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {var listView = SliverFixedExtentList(itemExtent: 56,delegate: SliverChildBuilderDelegate((_, index) => ListTile(title: Text('$index')),childCount: 10,));Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Center(child: CustomScrollView(slivers: [listView,listView,],),));}
}

8-1. 常用的Slivers

  • 可滚动组件对应的Sliver
名称功能对应组件
SliverList列表ListView
SliverFixedExtentList高度固定的列表ListView,指定itemExtent后
SliverAnimatedList添加/删除列表项可以执行动画AnimatedList
SliverGrid网格GridView
SliverPrototypeExtentList根据原型生成高度固定的列表ListView,指定prototypeItem后
SliverFillViewport包含多个子组件,每个都可以填满屏幕PageView
  • 子组件必须是Sliver
名称对应RenderBox容器
SliverPaddingPadding
SliverVisibility、SliverOpacityVisibility、Opacity
SliverFadeTransitionFadeTransition
SliverLayoutBuilderLayoutBuilder
  • 其他常用的Sliver
名称功能
SliverAppBar对应 AppBar,主要是为了在 CustomScrollView 中使用
SliverToBoxAdapter一个适配器,可以将 RenderBox 适配为 Sliver
SliverPersistentHeader滑动到顶部时可以固定住

本次分享就到这儿啦,我是鹏多多,如果您看了觉得有帮助,欢迎评论,关注,点赞,转发,我们下次见~

往期文章

  • 手把手教你搭建规范的团队vue项目,包含commitlint,eslint,prettier,husky,commitizen等等
  • Web Woeker和Shared Worker的使用以及案例
  • Vue2全家桶+Element搭建的PC端在线音乐网站
  • vue3+element-plus配置cdn
  • 助你上手Vue3全家桶之Vue3教程
  • 助你上手Vue3全家桶之VueX4教程
  • 助你上手Vue3全家桶之Vue-Router4教程
  • 超详细!Vue的九种通信方式
  • 超详细!Vuex手把手教程
  • 使用nvm管理node.js版本以及更换npm淘宝镜像源
  • vue中利用.env文件存储全局环境变量,以及配置vue启动和打包命令
  • 超详细!Vue-Router手把手教程

个人主页

  • CSDN
  • GitHub
  • 简书
  • 博客园
  • 掘金

相关文章:

flutter学习-day12-可滚动组件和监听

&#x1f4da; 目录 简介可滚动组件 SingleChildScrollViewListView separated分割线无限加载列表带标题列表 滚动监听和控制 ScrollController滚动监听NotificationListener滚动监听 AnimatedList动画列表滚动网格布局GridView 横轴子元素为固定数量横轴子元素为固定最大长度…...

LeetCode:967连续查相同的数字(DFS)

题目 返回所有长度为 n 且满足其每两个连续位上的数字之间的差的绝对值为 k 的 非负整数 。 请注意&#xff0c;除了 数字 0 本身之外&#xff0c;答案中的每个数字都 不能 有前导零。例如&#xff0c;01 有一个前导零&#xff0c;所以是无效的&#xff1b;但 0 是有效的。 …...

深入剖析NPM: Node包管理器的介绍和使用指南

导言&#xff1a;NPM&#xff08;Node Package Manager&#xff09;是JavaScript世界中最受欢迎的包管理器之一。它的出现大大简化了JavaScript开发过程中的依赖管理和模块化。本文将向您介绍NPM的基本概念、功能和常见用法&#xff0c;并为您提供一份详尽的NPM使用指南。 一、…...

AI视频-stable-video-diffusio介绍

介绍 stbilityai/stable-video-diffusion-img2vid-xt模型&#xff0c;由Stability AI开发和训练的基于散度的图像到视频生成模型。该模型可以接受一张静态图像作为条件,并生成出一个短视频。 该模型通过在SVD Image-to-Video [14帧]的基础上进行微调而来,可以生成576x1024分辨…...

day01-报表技术POI

前言 报表[forms for reporting to the higher organizations]&#xff0c;就是向上级报告情况的表格。简单的说&#xff1a;报表就是用表格、图表等格式来动态显示数据&#xff0c;可以用公式表示为&#xff1a;“报表 多样的格式 动态的数据”。 1、开发环境搭建 功能说…...

如何预防最新的.locked、.locked1勒索病毒感染您的计算机?

尊敬的读者&#xff1a; 近期&#xff0c;网络安全领域迎来一股新潮——.locked、.locked1勒索病毒的威胁&#xff0c;其先进的加密技术令人生畏。本文将深入剖析.locked、.locked1勒索病毒的阴谋&#xff0c;提供特色数据恢复策略&#xff0c;并揭示锁定恶劣行径的先锋预防手…...

实现两张图片的接缝线拼接

使用ORB算法检测特征点&#xff0c;并通过BFMatcher进行特征点匹配。然后&#xff0c;根据Lowes ratio test选择好的匹配点&#xff0c;并使用findHomography计算单应性矩阵。最后&#xff0c;使用warpPerspective将图像进行透视变换&#xff0c;然后将第二张图像粘贴到变换后的…...

基于JNI 实现 嵌套 List 类型参数解析

基于JNI 实现 嵌套 List 类型参数解析 背景分析解决 背景 在前面两篇文章中&#xff0c;我们总结了Java 调用 C/C SDK 的几种方案&#xff0c;分享了JNI在实践过程中的一些踩坑点&#xff0c;而在这篇文章将继续分享针对Java List类型及其嵌套类型&#xff0c;我们的JNI如何接…...

探索灵活性与可维护性的利器:策略(Strategy)模式详解

目录 ​编辑 1. 策略模式概述&#xff1a; 2. 主要角色&#xff1a; 3. 实例场景&#xff1a; 4. 具体实现步骤&#xff1a; 步骤一&#xff1a;定义策略接口 5. 使用策略模式的客户端代码&#xff1a; 总结&#xff1a; 我的其他博客 1. 策略模式概述&#xff1a; 策…...

压缩包文件暴力破解 -Server2005(解析)

任务五十一: 压缩包文件暴力破解 任务环境说明:Server2005 1. 通过本地PC中渗透测试平台Kali使用Nmap扫描目标靶机服务版本信息,将 Telnet 版本信息字符串 作为 Flag 提交; flag:Microsoft Windows XP telnetd 2. 通过本地PC中渗透测试平台Kali对服务器场景Windows进行渗透测…...

mars3d加载arcgis发布的服务,⽀持4523坐标

问题 1.从这个服务地址加载&#xff0c;具体在哪⾥去转坐标呢&#xff1f; 加个 usePreCachedTilesIfAvailable&#xff1a;false 参数即可 坐标系为4490的arcgis影像服务图层&#xff0c;配置后瓦片加载不出来&#xff0c;没报错 甚至可以跳转 没有看出问题&#xff0c;或者测…...

『K8S 入门』二:深入 Pod

『K8S 入门』二&#xff1a;深入 Pod 一、基础命令 获取所有 Pod kubectl get pods2. 获取 deploy kubectl get deploy3. 删除 deploy&#xff0c;这时候相应的 pod 就没了 kubectl delete deploy nginx4. 虽然删掉了 Pod&#xff0c;但是这是时候还有 service&#xff0c…...

十七、如何将MapReduce程序提交到YARN运行

1、启动某个节点的某一个用户 hadoopnode1:~$ jps 13025 Jps hadoopnode1:~$ yarn --daemon start resourcemanager hadoopnode1:~$ jps 13170 ResourceManager 13253 Jps hadoopnode1:~$ yarn --daemon start nodemanager hadoopnode1:~$ jps 13170 ResourceManager 15062 Jp…...

华为云CodeArts Deploy常见问答汇总

1.【Deploy】部署java项目&#xff0c;为什么通过springboot启动步骤启动失败了&#xff1f; 答&#xff1a;用户所部署的jar包源码并不是springboot框架&#xff0c;所以无法用springboot启动步骤启动&#xff0c;该步骤并不等同于java -jar 命令&#xff0c;需要使用shell脚…...

前后端交互—开发一个完整的服务器

代码下载 初始化 新建 apiServer 文件夹作为项目根目录&#xff0c;并在项目根目录中运行如下的命令&#xff0c;初始化包管理配置文件: npm init -y运行如下的命令&#xff0c;安装 express、cors: npm i express cors在项目根目录中新建 app.js 作为整个项目的入口文件&a…...

前端框架的虚拟DOM(Virtual DOM)

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…...

什么是http状态码?

什么是http状态码&#xff1f; 当浏览者访问一个网页时&#xff0c;浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前&#xff0c;此网页所在的服务器会返回一个包含 HTTP 状态码的信息头&#xff08;server header&#xff09;用以响应浏览器的请求。 ht…...

linux/CentOS 7安装Nginx

Nginx 是 C语言 开发&#xff0c;建议在 Linux 上运行&#xff0c;当然&#xff0c;也可以安装 Windows 版本&#xff0c;本篇则使用 CentOS 7 作为安装环境。 Nginx一般使用非root账号安装&#xff0c;如果还没有非root账号&#xff0c;先创建账号 创建账号 创建组&#xf…...

软件工程期末复习+数据仓库ETL

一、软件工程 请用基本路径测试方法为下列程序设计测试用例&#xff0c;并写明中间过程&#xff1a; 第1步&#xff1a;画出流程图 1.菱形用于条件判断。用在有分支的地方。 2.矩形表示一个基本操作。 3.圆形是连接点 第2步&#xff1a;计算程序环路复杂性 流图G的环路复杂…...

学习C语言——体会计算机中的0和1

/* 把hello隐写入一个整型数组,这个小程序可以考察是否清楚数据在内存中存储的具体细节。 具体的说&#xff0c;int类型在小端机器上的存储方式是高位在高地址&#xff0c;低位在低地址&#xff0c;从视觉习惯上和我们的日常书写习惯相反&#xff1b; char类型占用…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...