通用商城项目(下)

news2025/1/14 1:24:39

记录一些踩坑的地方,以及理顺一些思路。

通过管理系统页面,完成商品属性分组和商品属性(基本属性)关联维护

属性表 与 属性组表 的功能完善:显示属性组与属性表的一对多关系

前端

1. 引入组件,是否显示使用v-if,但是还要注意引入的组件本身,是否自己也有 :visible.sync="visible"这样的属性。只有当两层是否显示的变量都为true的时候,才会显示。

2. 使用子组件的方法,使用ref

3. 需要在执行完毕后,才立即执行的情况,使用this.$nextTick(()->{  lambda表达式的方法体 })

移除中间表,即连接属性表与属性组表的AttrAttrgroupRelation表

后端

需求说明:

批量删除关联表内容。

我的方案问题及解决方案:

1.我写了(@RequestBody Map params) 来获取参数,结果参数都拿不到,直接报错。

        前端传递的问题。使用postman可以正常传输。

        这个方案不好:①获取参数麻烦;②传递数组也不方便

2.还有底层不知道给两个基本参数,还是给一个对象,比较好?

        传给一个关联表的entity对象。可以使用@RequestBody来直接封装到该自定义的entity里面。

        而且参数使用数组的形式,前端使用Json,只有数组,没有集合格式

        再在后端转为集合,因为dao层foreach遍历,传参用的是集合。这样便可以实现批量删除

3.我的想法,要先去mysql查到要删除的数据,然后再去mysql删除,多了一个查询的步骤。 

4.想返回受影响的行数。

        测试发现,在dao层返回类型设为Integer,是可以直接返回受影响行数的,不用额外写代码。

细节踩坑:

1、在dao层的接口方法,依然要使用注解@Param 传参!

        通过删除该注解发现,参数会值为空,且不能正确运行。

2、测试数据的类型要求数组,所以格式要求“ [  ] ”这样来表示数组!

        通过在postman,哪怕是单一entity,没有使用[ ],也发生了错误。

3、Mapper语句中,字段名(来自于mysql) = 值(来自于java的Entity)。

        没有写错,再次提醒而已。

4、找了2个小时的bug。在service层调用dao层的方法时,使用了this.方法,结果调的是service层自己,就变成了无限嵌套,导致出错。根本原因还是对这儿的this理解不够。

        错误原因:

        ① 错误写法形成的原因。之前的代码,因为有“工具类”(可能形容不准确)的存在,所以能使用this.方法,使得能通过this.方法,在service层调用dao层的对应方法。

        ② 出错的原因。因为当前方法是我在dao层自定义的,service没有进行实现,需要我自己调用dao层来实现,结果我写个this.方法,成了自己调用自己当前方法,就形成了没有返回的嵌套。

        最好的解决办法,不要使用this,代码规范有要求

查询某个商品属性分组可以关联的商品属性(基本属性),支持分页和条件检索

@RequestBody和@RequestParam区别全面详细

还是对this的理解不够深刻。为什么:

为什么在AttrServiceImpl.java就可以

        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                //终于看懂这个wrapper了,它是个变量,放在这儿作参数用的。
                wrapper
        );

在AttrgroupServiceImpl.java,就不可以

        IPage<AttrEntity> page = new AttrServiceImpl().page(
                new Query<AttrEntity>().getPage(params),
                wrapper
        );

显示可建立关联的基本属性

涉及多表联查,使用AB两表查询得到限制条件,通过限制条件,在C表直接分页查询完成。

新建属性组与基础属性的关联

调用service提供的接口,即可完成。

因为支持批量增加,所以参数是List类型的,使用@RequestBody进行传递

商品发布

SPU和SKU介绍

1、SPU的概述
1)SPU(Standard Product Unit):标准化产品单元
2)用简单的话来说就是一类商品,比如手机里的一种牌子,如小米,苹果,都是一类。然后加入具体的类型,如小米10、苹果X。那么它就是一个spu
2、sku的概述
1)SKU(Stock keeping Unit):库存保有单位
2)sku简单来说就是在spu原有的基础上加入具体的类型,如小米10,银色,8+128g。组合起来就是一个完整地sku。所以sku就是一类商品的各种样式的组合。
3、spu和sku的关系
1)spu和sku就是上下级关系,没有spu就没有sku。因为假如没有这一类商品,就没法谈这件商品具体的颜色尺寸
2)如下图:假如没有选择任何类型那么他就是一个单独的spu,但是当它选择了具体的颜色,版本,购买方式等等,那么他就是一个sku

完成商品发布页面


1.完成选择商品分类时,联动获取该分类下的品牌

指定商品分类后,自动显示可以选择的品牌列表

实现:

利用categoryId查询关联表,得到brandId,使用它查询brand表的行,并返回

注意:

1.当输入的categoryId没有时,会报异常

2.当输入的categoryId在关联表,找不到对应的brandId时,也会报错

因为这时的mysql的语句里面in()后面的内容为空,所以报异常

解决办法是,直接使用stream流进行处理,处理完的BrandEntity进行返回,这样允许返回为[]。


2.完成获取某个分类的关联的所有属性分组和这些属性分组关联的基本属性,并显示供发布选择

1. 当目前的实体类/对象,格式不能满足需求时,可以使用VO(View Object)视图对象
2. VO可以根据需求组合己有的实体类字段,或者增加,或者删除一些字段

难点:

1.多表查询。使用流式计算,提高效率。

2.使用BeanUtils.copyProperties(数据源,目的数据)将数据封装到VO里面。以前在JavaWeb的时候用过。

debug:

1.前后端的debug都没有反馈:居然是因为@PathVariable("catalogId") 括号里面的单词拼错了!

2.后端测试正确,前端不显示结果。原因是前端遍历子属性的名称,和后端不一致,导致无法遍历。将后端名称改为和前端一致,便解决了。

3.完成获取某个分类的销售属性,并显示供发布选择

debug:

1.因为不带查询条件,所以代码要判断查询条件是否为空,否则mysql会导致异常。

2.查询条件的字段,需要与mysql保持一致,否则也会引起异常。

3.检查前端的分隔符,split(",")里面的符号,和后端是否保持一致,同时注意中英文。


4.完成根据前面填写的多个销售属性,构建成商品SKU信息(也就是各种组合关系)

 由前端页面完成


5.完成保存商品信息功能

需要设计VO类:

1、通过前端获得提交的json格式的数据,在JSON在线解析及格式化验证 - JSON.cn里面选择,“json生成java实体

2、根据业务要求,修改生成类的类型,以及必要的增删

功能1-保存spu基本信息

创建数据库,使用renren-fast生成crud代码

复制/剪切到后端程序中

报错:

        java: 找不到符号
          符号:   类 SpuInfoEntity
          位置: 程序包 com.stein.steinliving.commodity.entity

解决办法:

        1.Maven 刷新(Reload All Maven Project)

        2.菜单栏:build->Build Module "xxxxxx”

上两步依然没有解决,实际解决:

        Maven,lifecircle-> clean。重新运行module即可。。

bug:

        前端点击继续添加,如果不重新手动选择categoryId和品牌brand,那么前端显示有数据,后端得不到,数据库内会显示为null。

功能2-保存spu图片描述url

开始认为是一对多,使用一个id+多行decript保存;结果是用“,”逗号分割,保存在一行里面。

所以当初设计的时候,mysql对应的字段属性是LONGTEXT。

/**
* 商品 id
* 因为 commodity_spu_info_desc 表的 id 不是自增长的,而是我们指定的
* 因此,我们这里给 spuId 标识上 @TableId(type = IdType.INPUT)
* , 否则底层的 sql 语句时不会生成添加 supId sql 语句 ( 可以通过日志输出看看 )
*/
@TableId ( type = IdType.INPUT )
private Long spuId ;

功能3-保存spu图片集信息

功能4-保存spu的基本属性/规格参数

功能5-保存sku的基本信息

注意字段的命名:

因为mysql不区分大小写,所以将java属性的spuId,写作spu_id。不按照这个格式进行对应,可能会出错。

功能6-保存sku的图片信息

完善上传功能:

在前端的src/components/upload/multiUpload.vue文件下

<el-upload> 中的action进行设置,改为自己的oss地址,比如

action="http://xxxxxx.oss-cn-beijing.aliyuncs.com"

功能7-保存sku的销售属性

spu管理页面

添加订阅发布功能

因为要使用到订阅发布功能,所以我们需要做如下操作:
1.使用npm添加依赖:npm install --save pubsub-js

(失败的话使用此命令:cnpm install --save pubsub-js)

2.修改:在src下的views/main.js,增加语句
import cloneDeep from 'lodash/cloneDeep'
import PubSub from 'pubsub-js'

3.挂载全局下面添加:

Vue.prototype.PubSub = PubSub // 组件发布订阅消息

完善分页检索功能

其中的模糊检索:

wrapper.and(w->{
        w.eq("id",key).or().like("spu_name",key);
    });

完善“上架”和“下架”

1.先编写dao层。

        可以使用快捷键alt+enter,找mybatis的选项,自动填充@注解

        继续使用快捷键,找mybatis的选项,自动完善要实现的result部分

void productUpOrDown(@Param("spuId") Long spuId, 
@Param("statusCode") Integer statusCode);

实现语句:

        先在mysql里面测试语句是否正确,再写到实现语句

2.完善service层

3.controller层进行接口调用。

sku管理页面

同上

1.引入新页面打不开,可以重启下前端。

2.查看前端检索条件,注意看条件的名称:

key: this.dataForm.key,
catalogId: this.dataForm.catalogId,
brandId: this.dataForm.brandId,
min: this.dataForm.price.min,
max: this.dataForm.price.max

然后判断出封装在哪个变量:this.dataForm,然后输出查看:

console.log("检索条件=>",this.dataForm)

3.检索条件。价格区间:

这儿给max加了一条不为“0”的限制条件。

因为前端默认min、max=0。不利于初始化显示。

        //这儿的min和max是在price的子属性上,也是这么取吗?
        // 是的。因为封装的时候是遍历price的属性再进行封装的。
        //这儿是比较的数字,还是使用String接收吗? 是的
        //如何比较的大小? ge(GreatEqual),le(LittleEqual)
        String min = (String)params.get("min");
        if(StringUtils.isNotBlank(min)){
            wrapper.ge("price",min);
        }

        String max = (String)params.get("max");
        if(StringUtils.isNotBlank(max) && !"0".equals(max)){
            wrapper.le("price",max);
        }

搭建客户端显示的首页面

Thymeleaf的导入/引入

1.将资源包中的resources文件解压,放到后端项目的中的resources中。

2.maven中引入thymeleaf。在pom.xml中添加,不设置版本号,由版本仲裁控制

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

3.application.properties设置关闭缓存,便于随时刷新变化。

        spring.thymeleaf.cache=false

4.添加前端web控制层。

@Controller
public class IndexController {
    //响应用户请求首页面
    @GetMapping(value={"/","/index.html"})
    private String indexPage(){
        // 默认找到就是"classpath\templates"+"index"+".html"
        return "index";
    }
}

5.index.html文件引入命名空间。否则后期使用th标签时,无法识别。

文件路径:src/main/resources/templates/index.html

<html lang="en"xmlns th="http://www.thymeleaf.org">

首页显示1级目录

首页显示2、3级目录

1.创建2-3级VO类的数据结构

2.实现VO类数据的封装

2.1逻辑删除

通过查询发现,返回的数据不会有逻辑删除的内容。回忆之前逻辑删除的实现方法:

2.1.1  修改 hspliving\hspliving-commodity\src\main\resources\ application.yml
mybatis-plus:
    mapper-locations: classpath:/mapper/**/*.xml
    global-config:
        db-config:
            id-type: auto #配置主键自增
            logic-delete-value: 0 # 逻辑已删除值(默认为 1, 提示:调整成我们自己的)
            logic-not-delete-value: 1 # 逻辑未删除值(默认为 0 提示:调整成我们自己的)

2.1.2 属性添加响应的注解

        @TableLogic
        private Integer isShow ;

2.2 categoryService层编写方法

2.2.1 可以编写一个测试类,随时查看返回值是否正确

@Controller
public class Test {
    @Resource
    private CategoryService categoryService;

    @RequestMapping("/t1")
    @ResponseBody  //返回Json格式的数据。使用了便没有报错
    public Map<String, List<CategoryLevel2OV>> test(){
        Map<String, List<CategoryLevel2OV>> categoryLevelJson
                = categoryService.getCategoryLevelJson();
        return categoryLevelJson;
    }
}

2.2.2代码实现

@Override
    public Map<String, List<CategoryLevel2OV>> getCategoryLevelJson() {

        List<CategoryEntity> categoryList = this.baseMapper.selectList(null);
        //System.out.println(categoryList.toString());

        // 1级->2级->3级 再组装

        //获取1级分类
        List<CategoryEntity> level1 = getCategoryByParentId(categoryList, 0l);

        //通过流,遍历1级分类,并把数据进行封装,并从List转换为前端需要的Map
        Map<String,List<CategoryLevel2OV>> categoryMap = level1.stream().collect(Collectors.toMap(k -> {
            return k.getId().toString();
        }, v -> {
            //第二级的封装
            //先获取2级分类
            List<CategoryEntity> level2
                    = getCategoryByParentId(categoryList, v.getId());
            List<CategoryLevel2OV> level2OV = level2.stream().map(l2 -> {
                CategoryLevel2OV categoryLevel2 = new CategoryLevel2OV();
                categoryLevel2.setCatalog1Id(v.getParentId().toString());
                categoryLevel2.setId(v.getId().toString());
                categoryLevel2.setName(v.getName());

                //第三级的封装
                List<CategoryEntity> level3 = getCategoryByParentId(categoryList, l2.getId());
                List<CategoryLevel2OV.Catalog3List> level3VO = level3.stream().map(l3 -> {
                    CategoryLevel2OV.Catalog3List level3Entity = new CategoryLevel2OV.Catalog3List();
                    level3Entity.setId(l3.getId().toString());
                    level3Entity.setName(l3.getName());
                    level3Entity.setParentCId(l3.getParentId().toString());
                    return level3Entity;
                }).collect(Collectors.toList());
                categoryLevel2.setCatalog3List(level3VO);

                return categoryLevel2;
            }).collect(Collectors.toList());
            return level2OV;
        }));

        return categoryMap;
    }


    //私有方法:起到一个筛选作用。在数据列表中,筛出符合条件的的categoryEntities。
    private List<CategoryEntity> getCategoryByParentId(List<CategoryEntity> selectList, Long parentId) {
        List<CategoryEntity> categoryEntities = selectList.stream().filter(item -> {
            return item.getParentId().equals(parentId);
        }).collect(Collectors.toList());
        return categoryEntities;
    }

因为它是一个映射,所以返回类型是

3.连接前端

3.1找到前端发送Ajax请求的位置:

src\main\resources\static\index\js\catalogLoader.js,该js文件就是向服务器发出ajax请求,返回第2级和第3级json数据,然后由前端人员完成显示【我们直接使用即可】

由这句$.getJSON("index/catalog.json", function (data)可以看出访问路径为:"index/catalog.json",由此设置后端访问接口

3.2完善前端属性,便于数据显示

完善属性,便可在首页正常显示。

<a href="#" class="header_main_left_a" th:attr="ctg-data=${category.id}">

但是在控制台的data不能正常显示,显示一些类似当前行高的数字,随鼠标滑轮变化。看不懂。。

0
secend.js:3 0.9090908765792847
secend.js:3 6.363636016845703
secend.js:3 19.09090805053711
secend.js:3 40.909088134765625
secend.js:3 70.90908813476562
secend.js:3 108.18181610107422
secend.js:3 148.1818084716797
secend.js:3 185.4545440673828
secend.js:3 215.4545440673828
secend.js:3 235.4545440673828
secend.js:3 244.5454559326172
secend.js:3 246.36363220214844
secend.js:3 245.4545440673828
secend.js:3 240.90908813476562
secend.js:3 234.5454559326172
secend.js:3 224.5454559326172
secend.js:3 209.09091186523438

完善搜素首页

1.创建OV类

        注意Thymeleaf是通过对象传输的,而不是Json

2.实现搜索功能-Service层

3.实现数据的二次封装。添加Model参数,用于传输属性。-Controller层

4.前端调用封装到Model里面的数据。

添加Thymeleaf的命名空间

找到显示的list.html文件,通过搜索显示的实例里面的价格,找到对应的属性,进行关联。

完善分页导航栏

完善搜索框搜索

只搜索状态为上架的商品

1.添加搜索spuInfo表的dao层,完成搜索,获得上架spuIds

2.把原来的搜索添加spuId这个搜索条件,限定搜索范围在spuIds上架状态

注意:

要判断spuIds.size>0,如果真,则执行限定in();

如果假,便直接返回。为了统一返回内容为SearchResult,便开始重构

重构搜索功能

//返回购买用户检索的结果PageUtils->SearchResult / Result

完善分页查询功能,用户点击某页超链接,显示对应页的数据

分析源代码,查看导航页的参数属性构成情况。

没有输入,便按照默认设置的参数执行。

添加前端导航条,分页代码

    //分页请求
    $(".page_a").click(function () {
        var pn = $(this).attr("pn");
        var href = location.href;
        if (href.indexOf("page") != -1) {
            //替换, 这里的"page" 是因为我们后台分页插件是按照 page 这个参数来当做当前页
            //的参数
            //所以写成 page ,同学们应当根据你的后台是安装什么参数名来接收当前页进行相应改变
            location.href = replaceParamVal(href, "page", pn);
        } else {
            //增加 pageNuw
            if (href.indexOf("?") != -1) {
                location.href = location.href + "&page=" + pn;
            } else {
                location.href = location.href + "?page=" + pn;
            }
        }
        return false;
    })

在搜索框,保留检索关键字

原理:前端发送到 -> 后端,添加类字段,保存keyword,通过result回传 -> 前端,回显

1.前端原始代码,通过placeholder显示默认内容。此时内容固定显示

<input id="keyword_input" type="text" placeholder="家居~"/>

2.后端封装返回数据的SearchResultOV.java类,添加keyword属性

3.业务代码,完善SkuInfoServiceImpl.java类中,keyword的内容封装

//添加搜索框回显内容
//三元操作符
searchResultOV.setKeyword(params.get("keyword")==null?"":params.get("keyword").toString());

4.前端回显

<input id="keyword_input" th:value="${result.keyword}" 
type="text" placeholder="家居~"/>

通过value取出result.keyword进行回显。

加入Nginx-完成反向代理、负载均衡和动静分离

https://blog.csdn.net/weixin_49764008/article/details/132887378?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22132887378%22%2C%22source%22%3A%22weixin_49764008%22%7D

完成 Nginx的添加

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

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

相关文章

qgroundcontrol源码Andriod平台编译

1.下载QGC(qgroundcontrol)源码: 2.安装Qt5.15.2 3.配置Android平台工具集: 4.打开QGC项目文件: 5.安卓工程输出路径: 6.创建签名文件: 7.右击工程,然后选择Build 8.修改生成工程gradle.properties(Global Properties)增加下面内容: org.gradle.jvmargs-Xmx1536M --add-export…

UGNX配置许可服务器

UG客户端配置许可服务器&#xff0c;第一次安装完成或修改成其他许可服务器  打开菜单栏&#xff0c;找到Siemens NX目录->许可证工具->许可工具  切换到环境设置&#xff0c;设置许可服务器&#xff0c;点击编辑&#xff0c;弹出编辑框输入端口服务器IP。  输入…

[字符串和内存函数]strcat和strncat的区别

CPlus中对strcat的介绍 /* strcat example */ #include <stdio.h> #include <string.h>int main () {char str[80];strcpy (str,"these ");strcat (str,"strings ");strcat (str,"are ");strcat (str,"concatenated.");p…

进程间通信(IPC)的方法:共享内存

共享内存(shared memory)是可用IPC技术中最快的一种。一旦内存被映射到共享内存区域的进程的地址空间中&#xff0c;在进程之间传递数据时就不会发生内核(kernel)参与。然而&#xff0c;在共享内存区域存储和提取数据时&#xff0c;进程之间需要某些形式的同步(例如互斥锁、条件…

Spring Boot的魔法:构建高效Java应用的秘诀

文章目录 1. 自动配置&#xff08;Auto-Configuration&#xff09;2. 起步依赖&#xff08;Starter Dependencies&#xff09;3. 内嵌Web服务器&#xff08;Embedded Web Server&#xff09;4. 外部化配置&#xff08;Externalized Configuration&#xff09;5. Spring Boot Ac…

每日一题 213. 打家劫舍 II

难度&#xff1a;中等 思路&#xff1a; 首先不看成环&#xff0c;只是当作列表&#xff0c;那么对于第 i 间房&#xff0c;到 i 为止的最高偷窃金额为 f(i) max(f(i - 1), f(i - 2) nums[i])分析递推关系第一点&#xff0c;不管 i - 2 处的房子是否偷窃&#xff0c;i 处的…

【基础篇】ClickHouse 表结构设计

文章目录 1. ClickHouse 表结构设计1. 表的创建与标准SQL的差异1. 创建普通表2. 创建物化视图3. 创建分布式表 2. 表引擎1. MergeTree:2. Log:3. Memory:4. Distributed:5. Kafka:6. MaterializedView:7. File和URL: 3. MergeTree 家族3.1. MergeTree:3.2. ReplacingMergeTree:…

Nacos单机启动的两种方式

说明&#xff1a;直接双击nacos的启动脚本&#xff0c;默认是集群&#xff08;cluster&#xff09;的方式&#xff1b; 需要单机启动&#xff0c;有以下两种方式&#xff1b; 方式一&#xff1a;命令行 在当前目录打开命令窗口&#xff0c;输入以下命令启动nacos startup.…

jdk1.8堆内存学习

jdk1.8堆内存启动时控制参数图解 堆大小年轻代&#xff08;Young Generation&#xff09;年老代&#xff08;Old Generation&#xff09; GC相关 -Xnoclassgc&#xff1a;关闭JVM垃圾回收功能 -XX:UseSerialGC&#xff1a;使用Serial垃圾收集器&#xff0c;单线程串型收集器&…

Linux安装包 | Git使用 | NFC搭建

dpgt使用 当谈到基于 Debian 的操作系统中的软件包管理工具时&#xff0c;dpkg 是一个重要的工具。它是 Debian 系统中用于安装、升级、配置和卸载软件包的命令行工具。以下是对 dpkg 的详细介绍&#xff1a; 软件包管理&#xff1a;dpkg 可以管理系统中的软件包。它可以安装单…

Acwing 829. 模拟队列

Acwing 829. 模拟队列 题目描述思路讲解代码展示 题目描述 思路讲解 队列是先进先出&#xff0c;类比排队买饭 代码展示 #include <iostream>using namespace std;const int N 100010;int m; int q[N], hh, tt -1;int main() {cin >> m;while (m -- ){string …

ArmSoM-W3之RK3588 Debian11详解

1. 简介 RK3588从入门到精通Debian 是⼀种完全⾃由开放并⼴泛⽤于各种设备的 Linux 操作系统。Rockchip在官⽅Debian发⾏版的基础上构建和适配了相关硬件功能 2. 环境介绍 硬件环境&#xff1a; ArmSoM-W3 RK3588开发板 软件版本&#xff1a; OS&#xff1a;ArmSoM-W3 Debia…

服务器中了DevicData勒索病毒怎么办?勒索病毒解密,数据恢复

近日&#xff0c;云天数据恢复中心收到许多中了勒索病毒的用户求助。其中有多位用户中的都是同一种勒索病毒&#xff0c;它就是DevicData勒索病毒。那接下来我们就从它的特征、处理方案以及后续维护三个方面来了解一下这种勒索病毒。 一、DevicData勒索病毒的特征 加密文件&am…

VSCode 远程开发,再也不用带电脑回家了~

VS Code几乎是所有的程序员必备的工具之一&#xff0c;据说全球一般的开发者都使用过VS Code这款工具。 今天为大家介绍一下 VS Code 实现远程办公的方法。 1、概 述 通常&#xff0c;我们都是每天到工作的办公室进行办公&#xff0c;但是&#xff0c;如果下班回家&…

【多线程案例】定时器

1. 定时器是什么&#xff1f; 定时器也是软件开发中的一个重要组件. 类似于一个 "闹钟". 达到一个设定的时间之后, 就执行某个指定好的代码. 定时器是一种实际开发中非常常用的组件. 比如网络通信中, 如果对方 500ms 内没有返回数据, 则断开连接尝试重连. 比如一个 …

【Markdown】图片缩放

▚ 01 原图表示 语法为&#xff1a; ![替代文本](图片链接地址)其中&#xff0c;替代文本是在无法显示图片时显示的替代文本&#xff0c;而图片链接是指向图片的URL或相对路径。 例如&#xff0c;插入Panda图片&#xff1a; ![panda](https://img-blog.csdnimg.cn/e5f3…

李开复:我家的AI是坠吼的

创新工场董事长、鸿海独立董事李开复&#xff0c;近日出席鸿海股东会暨媒体记者会时表示&#xff0c;人工智能&#xff08;AI&#xff09;是人类史上即将面临的最伟大技术革命&#xff0c;未来十年的改变将改写人类历史、重构所有产业&#xff0c;其发展大致可分三阶段&#xf…

uniapp风险等级(三级)

代码 ​ <template><view><view class"riskGrade"><label>风险等级: </label><span v-if"flag 0 || flag 1 || 2" class"item":style"[{background:flag0?color:flag1?color:flag2?color:}]"…

快速排序和归并排序的非递归形式

快速排序和归并排序都需要用递归的形式展开&#xff0c;那么有没有什么方法不需要递归就能实现归并和快速排序&#xff0c;有的&#xff01; 1.快速排序 我们可以借助栈来模拟递归。 递归的主要思想就是大事化小&#xff0c;小事化了。我们借助栈的 目的是将需要排序的“头” 和…

面试题:有了 for 循环 为什么还要 forEach ?

文章目录 **本质区别****for循环和forEach的语法区别****for循环和forEach的性能区别** js中那么多循环&#xff0c;for for…in for…of forEach&#xff0c;有些循环感觉上是大同小异今天我们讨论下for循环和forEach的差异。我们从几个维度展开讨论&#xff1a; for循环和fo…