第18章 JQuery DataTables初始化渲染显示与排序

1 System.Linq.AsyncIEnumerableExtensions (Data\Extensions\AsyncIEnumerableExtensions.cs)

namespace System.Linq

{

    /// <summary>

    /// 【异步枚举数扩展--类】

    /// <remarks>

    /// 摘要:

    ///     该类通过对System.Linq.Async中方法的自定义扩展,实现Linq中的SelectWhereAny等操作方法的异步实现,并通过自定义的异步Linq方法,进行求和、求累加、求总计和编组等操作。

    /// </remarks>

    /// </summary>

    public static class AsyncIEnumerableExtensions

    {

        /// <summary>

        /// 【等待选择】

        /// <typeparam name="TSource">泛型类型实例(1个指定类的类型实例,数据源)</typeparam>

        /// <typeparam name="TResult">泛型类型实例(通过“System.Linq.Async”操作筛选出符合条件的实例)</typeparam>

        /// <param name="source">“IEnumerable”实例进行存储的1个指定类型的数据源(枚举数接口实例=长串型,包含:数组、列表、字典等)</param>

        /// <param name="predicate">一个具有返回值的异步委托方法实例,方法实例用于从数据源中通过“System.Linq.Async”操作筛选出符合条件的实例。</param>

        /// <remarks>

        /// 摘要:

        ///     从数据源中通过“System.Linq.Async”操作筛选出所有符合条件的实例,并把这些实例存储到“IAsyncEnumerable”实例中。

        /// </remarks>

        /// <returns>

        ///    “IAsyncEnumerable”实例,该实例存储着通过“System.Linq.Async”操作筛选出所有符合条件的实例。

        /// </returns>

        /// </summary>

        public static IAsyncEnumerable<TResult> SelectAwait<TSource, TResult>(this IEnumerable<TSource> source,

            Func<TSource, ValueTask<TResult>> predicate)

        {

            return source.ToAsyncEnumerable().SelectAwait(predicate);

        }

    }

}

2 Services.Customers.Caching.CustomerCacheEventConsumer

uusing Core.Domain.Customers;

using Services.Caching;

namespace Services.Customers.Caching

{

    /// <summary>

    /// 摘要:

    ///     通过该类中的方法成员,在用户实体的1个实例执行插入、更新或持久化/逻辑删除操作后,为该实体所有相关实例的分布式缓存的强制移除操作提供数据支撑,同时避免用户实体的列表渲染显示出现的异常。

    /// </summary>

    public class CustomerCacheEventConsumer : CacheEventConsumer<Customer>

    {

    }

}

3 重构Services.Customers.CustomerService.GetAllCustomersAsync

 /// <param name="deleted">指示是否包含指定实体中所有的逻辑删除项,默认值:null,即该参数实例不参与筛选操作。</param>

        /// <param name="email">1个指定的电字邮箱字符串,默认值:null,即该参数实例不参与筛选操作。</param>

        /// <param name="username">1个指定的用户名/昵称,默认值:null,即该参数实例不参与筛选操作。</param>

        /// <param name="phone">1个指定的手机号,默认值:null,即该参数实例不参与筛选操作。</param>

        /// <param name="createdDateFrom">1个指定的用户注册开始日期,默认值:null,即该参数实例不参与筛选操作。</param>

        /// <param name="createdDateTo">>1个指定的用户注册结束日期,默认值:null,即该参数实例不参与筛选操作。</param>

        /// <param name="orderByFiled">1个指定的用于排序操作的排序字段字符串,默认值:null,即按照创建时间以倒序方式进行排序操作。</param>

        /// <param name="orderByType">1个指定的用于排序操作的排序排序方式,默认值:null,即按照创建时间以倒序方式进行排序操作。</param>

        /// <param name="pageIndex">当前页的页数值(“pageSize”结合,设定需要跳过指定实体实例的个数值),默认值:0,即不需要执行跳过操作。</param>

        /// <param name="pageSize">分页操作中每页最多显示实例的项()数值(“pageIndex”结合,设定需要跳过指定实体实例的个数值),默认值:int.MaxValue=2147483647</param>

        /// <param name="getOnlyTotalCount">指示数据源中否包含有实例,默认值:null,即该参数实例不参与筛选操作。</param>

        /// <summary>

        /// 【异步获取所有用户】

        /// <remarks>

        /// 摘要:

        ///     根据前端分页组件传递的参数实例,获取符合条件的用户表1指定页面内的持久化数据加载到1指定内存逻辑页面内。

        ///  说明:

        ///     该方法没有定义缓存操作,更没有定义缓存的移除操作。

        /// </remarks>

        /// <returns>

        /// 返回:

        ///    1指定内存逻辑页面内的用户实体的所有实例。

        /// </returns>

        /// </summary>

        public virtual async Task<IPagedList<Customer>> GetAllCustomersAsync(bool? deleted = null, string email = null, string username = null, string phone = null,

            DateTime? createdDateFrom = null, DateTime? createdDateTo = null, string orderByFiled = null, string orderByType = null,

            long pageIndex = 0, int pageSize = int.MaxValue, bool getOnlyTotalCount = false)

        {

            var customers = await _customerRepository.GetAllPagedAsync(query =>

            {

                //根据参数实例,执行筛选操作。

                if (deleted.HasValue)

                    query = query.Where(c => c.Deleted.Equals(deleted));

                if (createdDateFrom.HasValue)

                    query = query.Where(c => createdDateFrom.Value <= c.CreatedDate);

                if (createdDateTo.HasValue)

                    query = query.Where(c => createdDateTo.Value >= c.CreatedDate);

                if (!string.IsNullOrWhiteSpace(email))

                    query = query.Where(c => c.Email.Contains(email));

                if (!string.IsNullOrWhiteSpace(username))

                    query = query.Where(c => c.Username.Contains(username));

                if (!string.IsNullOrWhiteSpace(phone))

                    query = query.Where(c => c.Phone.Contains(phone));

                //根据参数实例,执行排序操作。

                if (string.IsNullOrWhiteSpace(orderByFiled) && string.IsNullOrWhiteSpace(orderByType))

                {

                    query = query.OrderByDescending(customer => customer.CreatedDate);

                }

                else if (!string.IsNullOrWhiteSpace(orderByFiled))

                {

                    if (string.IsNullOrEmpty(orderByType) || orderByType.Equals("asc", StringComparison.InvariantCultureIgnoreCase))

                    {

                        query = query.OrderBy(orderByFiled);

                    }

                    else if (orderByType.Equals("desc", StringComparison.InvariantCultureIgnoreCase))

                    {

                        query = query.OrderByDescending(orderByFiled);

                    }

                }

                return query;

            }, pageIndex, pageSize, getOnlyTotalCount);

            return customers;

        }

4 Services.Customers.CustomerService.GetCustomerByIdAsync

 /// <param name="customerId">用户实体1个指定实例的长整型编号值。</param>

        /// <summary>

        /// 【异步通过编号值获取用户】

        /// <remarks>

        /// 摘要:

        ///    直接从用户表中获用户实体的1个指定实例;或从分布式缓存数据库获取用户实体的1个指定实例(即使该实例处于逻辑删除状态,也获取该实例)

        /// </remarks>

        /// <returns>

        /// 返回:

        ///    用户实体的1个指定实例。

        /// </returns>

        /// </summary>

        public virtual async Task<Customer> GetCustomerByIdAsync(long customerId)

        {

            return await _customerRepository.GetByIdAsync(customerId,

                cache => cache.PrepareKeyForShortTermCache(EntityCacheDefaults<Customer>.ByIdCacheKey, customerId));

        }

5 Web.Areas.Admin.Factories.CustomerModelFactory.PrepareAvatarUrlAsync

/// <param name="customerId">1个指定的长整型值。</param>

        /// <summary>

        /// 【异步预处理头像图片】

        /// </summary>

        /// <remarks>

        /// 摘要:

        ///     获取1个指定用户头像图片的网络格式绝对路径字符串。

        /// </remarks>

        /// <returns>

        ///     1个指定用户头像图片的网络格式绝对路径字符串。

        /// </returns>

        public async Task<string> PrepareAvatarUrlAsync(long customerId)

        {

            string _avatarUrl = string.Empty;

            Customer _customer = await _customerService.GetCustomerByIdAsync(customerId);

            if (_customer != null)

            {

                if (string.IsNullOrEmpty(_customer.Avatar))

                {

                    string _path = _nopFileProvider.Combine(_nopFileProvider.WebRootPath, @"\images\Avatar\Default.jpg");

                    if (_nopFileProvider.FileExists(_path))

                    {

                        string _absoluteAvatarUrl = _nopFileProvider.GetVirtualPath(@"\images\Avatar\Default.jpg");

                        //URL格式路径字符中的第一个字符:“~/”

                        _absoluteAvatarUrl = _absoluteAvatarUrl.Replace("~/", string.Empty);

                        _avatarUrl = _webHelper.GetStoreHost() + _absoluteAvatarUrl;

                    }

                }

                else

                {

                    _avatarUrl = _webHelper.GetStoreHost().TrimEnd('/') + _customer.Avatar;

                }

            }

            return _avatarUrl;

        }

6 重构Web.Areas.Admin.Factories.CustomerModelFactory.PrepareCustomerListModelAsync

  /// <param name="searchModel">用户过滤筛选模型纪录的1个指定实例。</param>

        /// <summary>

        /// 【异步预处理用户分页列表模型纪录】

        /// <remarks>

        /// 摘要:

        ///     获取用户分页列表模型纪录的1个指定实例,为Jquery DataTable插件当前页渲染显示提供基本且必须的数据支撑。

        /// </remarks>

        /// <returns>

        ///      用户分页列表模型纪录的1个指定实例。

        /// </returns>

        /// </summary>

        public virtual async Task<CustomerListModel> PrepareCustomerListModelAsync(CustomerSearchModel searchModel)

        {

            //根据前端传递的用户过滤筛选模型纪录的1个指定实例,从用户表中获取(1逻辑页中的)相应行数的数据,并把这些数据存储到列表实例中。

            var customers = await _customerService.GetAllCustomersAsync(

               orderByFiled: searchModel.OrderBy, orderByType: searchModel.OrderDir.ToString(), pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize);

            //实例化当前用户分页列表模型纪录(“物理页”),为Jquery DataTable插件当前页渲染显示提供基本且必须的数据支撑。

            var model = await new CustomerListModel().PrepareToGridAsync(searchModel, customers, () =>

            {

                return customers.SelectAwait(async customer =>

                {

                    var customerModel = customer.ToModel<CustomerModel>();

                    customerModel.Avatar = await PrepareAvatarUrlAsync(customerModel.Id);

                    return customerModel;

                });

            });

            return model;

        }

7 Web\Areas\Admin\Views\Customer\Index.cshtml

<div class="content-header">

    <div class="container-fluid">

        <div class="row mb-2">

            <div class="col-sm-6">

                <div class="fs-3">用户列表</div>

            </div>

            <div class="col-sm-6">

                <ol class="breadcrumb float-sm-end">

                    <li class="breadcrumb-item">

                        @*resetRoleList:用于控制对弹出框的关闭和角色列表的刷新渲染*@

                        <button type="button" id="resetRoleList" class="btn btn-secondary me-3 d-none">

                            <i class="fa-solid fa-rotate-right"></i>

                            重置

                        </button>

                        <button type="button" onclick="OpenWindow('@(Url.Action("Create", "Role",  new {btnId = "resetRoleList"}))', 500, 500, true); return false;" class="btn btn-success float-end">

                            <i class="fas fa-plus"></i>

                            添加

                        </button>

                    </li>

                </ol>

            </div>

        </div>

    </div>

</div>

<!-- Main content -->

<div class="content">

    <div class="container-fluid">

        <div class="row">

            <div class="col-12">

                <!-- Default box -->

                <div class="card">

                    <div class="card-body">

                        <table id="example" class="table table-striped table-bordered nowrap projects" width="100%" cellspacing="0">

                        </table>

                    </div>

                    <!-- /.card-body -->

                </div>

                <!-- /.card -->

            </div>

        </div>

        <!-- /.row -->

    </div><!-- /.container-fluid -->

</div>

@section Scripts {

    <script type="text/javascript">

        var tableModel;

        $(document).ready(function () {

            tableModel = $("#example").DataTable({

                language: {

                    url: '../../lib/DataTables/DataTables-1.13.4/language/zh.json' //DataTables语言配置选项

                },

                processing: true,    //是否显示处理中...”(排序的时候,数据很多耗费时间长的话,也会显示这个)

                serverSide: true,  //是否开启服务器模式

                paging: true, //是否允许翻页

                lengthMenu: [10, 20, 50, 100], //Jquery DataTable插件下拉框控件中的数量选择内容。

                pageLength: 10, // 每页的行数的默认值:10

                searching: false, //是否在Jquery DataTable插件中显示搜索框控件。

                //autoWidth: true,   //自适应宽度

                bSort: true, //显示排序按钮

                pagingType: "numbers",//使用该类型,为在表中数据为空时,禁止在Jquery DataTable插件中,显示上页下页按钮。

                //当处理大数据时,延迟渲染数据,有效提高Datatables处理能力

                deferRender: true,

                order: [[8, "desc"]],//默认设置第8列以倒序方式对Jquery DataTable插件进行排序显示。

                ajax: {

                    url: "/Admin/Customer/CustomerList",

                    type: "POST",

                    datatype: "JSON",

                    cache: false,  //禁用缓存

                },

                columnDefs: [{  //设置列定义初始化属性

                    defaultContent: "", //为列设置默认的静态内容

                    targets: "_all"  //指定所有列

                }],

                //注意:"data"对应的字段(实体属性)的第1个字母必是小写,否则实体实例的值将不会被浏览器渲染出来。

                columns: [

                    {

                        data: "id", "title": "<input type='checkbox' id='checkAll' class='form-check-input checkBox20' />",

                        width: "25px",

                        orderable: false,//禁止当前列渲染显示排序按钮。

                        render: function (data, type, row, meta) {

                            return "<input type='checkbox' name='checkItem' value=" + data + " class='form-check-input checkBox20' />";

                        },

                    },

                    { data: "id", title: "编号", width: "100px" },

                    { data: "username", title: "用户名", autoWidth: true },

                    {

                        data: null,

                        title: "头像",

                        width: "65px",

                        orderable: false,//禁止当前列渲染显示排序按钮。

                        render: function (data, type, full, meta) {

                            return "<img  src='" + data.avatar + "'class='img-size-64'/>";

                        },

                    },

                    { data: "email", title: "邮箱", autoWidth: true },

                    { data: "phone", title: "手机", width: "100px", orderable: false },

                    {

                        data: "active",

                        title: "可用",

                        width: "50px",

                        orderable: false,

                        //禁止当前列渲染显示排序按钮。

                        render: function (data, type, row, full, meta) {

                            //console.log(data);

                            if (data) {

                                return "<span class='badge bg-success'>激活</span>";

                            }

                            else {

                                return "<span class='badge bg-danger'>禁用</span>";

                            }

                        },

                    },

                    {

                        data: "deleted",

                        title: "删除",

                        width: "50px",

                        orderable: false,//禁止当前列渲染显示排序按钮。

                        render: function (data, type, row, full, meta) {

                            //console.log(data);

                            if (data)

                            {

                                return "<span class='badge bg-danger'>已经删除</span>";

                            }

                            else

                            {

                                return "<span class='badge bg-success' style='letter-spacing: 8px; text-indent: 8px; '>可用</span>";

                            }

                        },

                    },

                    {

                        data: "createdDate",

                        title: "创建日期",

                        width: "100px",

                        render: function (data, type, full, meta) {

                            //console.log(data);

                            //console.log(type);

                            //console.log(full);

                            //console.log(meta);

                            //时间格式化

                            return moment(data).format("YYYY-MM-DD HH:mm:ss");

                        }

                    },

                    {

                        data: null,

                        width: "100px",

                        orderable: false,//禁止当前列渲染显示排序按钮。

                        render: function (data, type, row, full, meta) {

                            return "<a href='#' class='btn btn-sm btn-info me-3' >编辑</a>"

                                + "<a href='#' class='btn btn-sm btn-danger' οnclick=deleteData('" + data.id + "'); >删除</a>";

                         },

                    },

                ] 

 

            });

        });

    </script>

}

230528_018ShopRazor(JQuery DataTables初始化渲染显示与排序)。

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

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

相关文章

C++进阶 —— set

目录 一&#xff0c;set介绍 二&#xff0c;set使用 一&#xff0c;set介绍 set是按照特定次序存储元素的关联式容器&#xff0c;元素不可重复&#xff1b;set中的元素不能在容器中修改(元素总是const)&#xff0c;但是可从容器中插入和删除它们&#xff1b;set中的元素总是按…

【测试报告】个人博客系统自动化测试报告

文章目录 项目背景项目功能测试计划功能测试测试用例执行测试的操作步骤 自动化测试设计的模块、自动化运行的结果、问题定位的结果自动化测试优点 项目背景 对于一个程序员来说&#xff0c;定期整理总结并写博客是不可或缺的步骤&#xff0c;不管是对近期新掌握的技术或者是遇…

代码随想录算法训练营第五十三天 | 力扣 1143.最长公共子序列, 1035.不相交的线, 53. 最大子序和

1143.最长公共子序列 题目 1143. 最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符…

SpringBoot——原理(自动配置+原理分析-源码跟踪)

源码跟踪 从Springboot的启动类进入&#xff0c;进行分析. 源码跟踪技巧 在以后接触各种框架的时候&#xff0c;如果需要查看源码&#xff0c;需要找到关键点和核心流程&#xff0c;先在宏观对整个原理和流程有一个认识&#xff0c;之后再去了解其中的细节。 按住Ctrl左键进…

怎么实现常用网络接口自动化测试框架应用?

一、RESTful&#xff08;resource representational state transfer)类型接口测试 (一&#xff09;GUI界面测试工具&#xff1a;jmeter 1、添加线程组 2、添加http请求 3、为线程组添加察看结果树 4、写入接口参数并运行 5、在查看结果树窗口查看结果 6、多组数据可增加CSVDat…

基于物理信息的神经网络(Physics-informed Neural Networks;PINNs)Part-1(简单介绍)

【摘要】 基于物理信息的神经网络&#xff08;Physics-informed Neural Networks&#xff0c;简称PINNs&#xff09;&#xff0c;是一类用于解决有监督学习任务的神经网络&#xff0c;它不仅能够像传统神经网络一样学习到训练数据样本的分布规律&#xff0c;而且能够学习到数学…

UFS 2 -UFS架构简介2

UFS 2 -UFS架构简介2 1 UFS架构简介1.1 System Boot and Enumeration1.2 UFS Interconnect (UIC) Layer1.2.1 UFS Physical Layer Signals1.2.2 MIPI UniPro1.2.3 MIPI UniPro Related Attributes 1.3 UFS Transport Protocol (UTP) Layer1.3.1 Architectural Model1.3.1.1 Cli…

图解max{X,Y}和min{X,Y}并求相关概率

图解max{X,Y}和min{X,Y}并求相关概率 对max{X,Y}或min{X,Y}进行分解再求解 P ( m a x { X , Y } ≥ c ) P [ ( X ≥ c ) ∪ ( Y ≥ c ) ] P ( m a x { X , Y } ≤ c ) P [ ( X ≤ c ) ∩ ( Y ≤ c ) ] P ( m i n { X , Y } ≥ c ) P [ ( X ≥ c ) ∩ ( Y ≥ c ) ] P ( m i…

k8s功能优势应用场景介绍(一)

一&#xff0c;K8S功能: 1、数据卷 pod中容器之间共享数据&#xff0c;可以使用数据卷 2、应用程序健康检查 容器内服务可能进程阻塞无法处理请求&#xff0c;可以设置监控检查策略保证应用健壮性 3、复制应用程序实例 控制器维护着pod副本数量&#xff0c;保证一个pod或一组同…

C++11 auto类型推导

1.类型推导 C11引入了auto 和 decltype 关键字实现类型推导&#xff0c;通过这两个关键字不仅能方便地获取复杂的类型&#xff0c;而且还能简化书写&#xff0c;提高编码效率。 auto 类型推导的语法和规则 在之前的 C 版本中&#xff0c;auto 关键字用来指明变量的存储类型…

Allure测试报告定制全攻略,优化你的Web自动化测试框架!

目录 前言&#xff1a; 1. Allure测试报告简介 2. Web自动化测试框架简介 3. 封装Web自动化框架 3.1 安装Selenium 3.2 封装Selenium 3.3 定制Allure测试报告 3.3.1 适配翻译插件 3.3.2 定制测试报告样式 4. 示例代码 5. 总结 前言&#xff1a; 随着现在Web应用的普…

SciencePub学术 | 计算机科学类重点SCIEI征稿中

SciencePub学术刊源推荐: 计算机科学类SCI&EI征稿中&#xff01;录用率高&#xff0c;自引率低&#xff0c;进展顺利。信息如下&#xff0c;录满为止&#xff1a; 一、期刊概况&#xff1a; 【期刊简介】IF&#xff1a;4.0-4.5↑&#xff0c; JCR 2区&#xff0c;中科院3区…

SpringAOP简介及实现(包含切面、切点、连接点和通知)

目录 1.什么是AOP、SpringAOP&#xff1f; 2.AOP的组成 3.SpringAOP的实现 4.切点的表达式 1.什么是AOP、SpringAOP&#xff1f; 在学习SpringAOP之前&#xff0c;我们得先了解一下什么是AOP。AOP是一种面向切面编程的思想。那什么是切面呢&#xff1f;它其实是对某一类事情…

【HR专用】Vue+SpringBoot,实现人才招聘库的开发(后端部分)

人才招聘库是企业用于储存和管理潜在候选人信息的数据库。通常情况下&#xff0c;这些候选人可能已经应聘过公司的职位&#xff0c;也可能是通过其他途径获取的&#xff0c;例如社交网络、招聘网站等。 对于一个中小公司来说&#xff0c;人力资源部绝对是一个重要部门&#xff…

测试类型(单元、集成、系统或手动测试)

测试类型(单元、集成、系统或手动测试) 单元测试 单元是系统的单个组件&#xff0c;例如类或单个方法。孤立地测试单元称为单元测试。 优点&#xff1a;速度快/易控/易写 缺点&#xff1a;缺乏现实性/无法捕获所有错误&#xff08;例如与其他组件或服务的交互&#xff09; 单元…

Arthas-JVM相关命令使用

tip&#xff1a;作为程序员一定学习编程之道&#xff0c;一定要对代码的编写有追求&#xff0c;不能实现就完事了。我们应该让自己写的代码更加优雅&#xff0c;即使这会费时费力。 开头&#xff1a; 我们先说下生产使用频率较高的有哪些&#xff1a;dashboard、heapdump、jvm…

【连续介质力学】二阶张量的图像表示

二阶张量在特定方向的投影 法向和切向分量 二阶张量T投影到 n ^ \hat n n^方向的结果是 t ⃗ ( n ^ ) T ⋅ n ^ \vec t^{(\hat n)}T \cdot \hat n t (n^)T⋅n^&#xff0c;其中 t ⃗ ( n ^ ) \vec t^{(\hat n)} t (n^)可以分解成&#xff1a; t ⃗ ( n ^ ) T ⃗ N T ⃗ S…

2023年上半年系统规划与管理师上午真题及答案解析

1.香农用概率来定量描述信息的公式如下&#xff0c;其中H(x)表示X的( )&#xff0c;Pi是( )出现第i种状态的( )。 A.信息熵 事件 概率 B.总熵 单位 概率 C.信息熵 单位 概率 D.总熵 单位 度量 2.信息传输模型中&#xff0c;( )负责信息的向外传播&#xff0c;( )负责…

VSLAM视觉里程计总结

相机模型是理解视觉里程计之前的基础。视觉里程计&#xff08;VIO&#xff09;主要分为特征法和直接法。如果说特征点法关注的是像素的位置差&#xff0c;那么&#xff0c;直接法关注的则是像素的颜色差。特征点法通常会把图像抽象成特征点的集合&#xff0c;然后去缩小特征点之…

Android 应用快捷ShortcutManager与ShortcutManagerCompat详解与实战(二)

一、介绍 之前我已通过一篇文章介绍了应用快捷的接入与Demo。如果还未看过上一篇的文章可以先了解入门。 传送门&#xff1a;Android 应用快捷(shortcut)功能的详解(一)_蜗牛、Z的博客-CSDN博客 有创建自然就会有管理&#xff0c;否则一个完美的方案不应该这么被推荐出来。如何…