android 日程安排view,RecyclerView 列表控件中简单实现时间线

时间

时间,时间,时间啊;走慢一点吧~

看见很多软件中都有时间线的东西,貌似天气啊,旅游啊什么的最多了;具体实现方式很多,在本篇文章中讲解一种自定义View封装的方式。

效果

先来看看效果。

1440469250572021.png

分析

软件中,可以看见前面的时间线也就是线条加上圆圈组成;当然这里的圆圈与线条也都是可以随意换成其他的,比如图片等等。

当然这里最简单的来说,是上面一个线条,然后一个圆圈,然后下面一个线条;上线条在第一条数据时不做显示,下线条在最后一条数据时不做显示。

1440469277121276.png

这里自定义布局部分也就是把旁边的线条与圆圈封装到一起,并使用简单的方法来控制是否显示。 当封装好了后,与旁边的文字部分也就是水瓶方向的线性布局了,然后设置为每一个的RecyclerView 的Item的布局也就完成了。

控件

控件很简单,首先我们继承View,取名为 TimeLineMarker 就OK。

Attrs 属性

开始控件之前先准备好需要的属性。<?xml  version="1.0" encoding="utf-8"?>

在这里也就准备了线条的大小、开始线条、结束线条、中间标示部分及大小。

属性与现实private int mMarkerSize = 24;

private int mLineSize = 12;

private Drawable mBeginLine;

private Drawable mEndLine;

private Drawable mMarkerDrawable;

@Override

protected void onDraw(Canvas canvas) {

if (mBeginLine != null) {

mBeginLine.draw(canvas);

}

if (mEndLine != null) {

mEndLine.draw(canvas);

}

if (mMarkerDrawable != null) {

mMarkerDrawable.draw(canvas);

}

super.onDraw(canvas);

}

两个大小属性,3个具体的Drawable,然后在onDraw方法中进行具体的显示也就OK。

构造与属性初始化

在上面我们定义了属性,在这里我们在构造函数中获取XML所设置的属性。public TimeLineMarker(Context context) {

this(context, null);

}

public TimeLineMarker(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public TimeLineMarker(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

init(attrs);

}

private void init(AttributeSet attrs) {

// Load attributes

final TypedArray a = getContext().obtainStyledAttributes(

attrs, R.styleable.TimeLineMarker, 0, 0);

mMarkerSize = a.getDimensionPixelSize(

R.styleable.TimeLineMarker_markerSize,

mMarkerSize);

mLineSize = a.getDimensionPixelSize(

R.styleable.TimeLineMarker_lineSize,

mLineSize);

mBeginLine = a.getDrawable(

R.styleable.TimeLineMarker_beginLine);

mEndLine = a.getDrawable(

R.styleable.TimeLineMarker_endLine);

mMarkerDrawable = a.getDrawable(

R.styleable.TimeLineMarker_marker);

a.recycle();

if (mBeginLine != null)

mBeginLine.setCallback(this);

if (mEndLine != null)

mEndLine.setCallback(this);

if (mMarkerDrawable != null)

mMarkerDrawable.setCallback(this);

}

Drawable 的位置与大小初始化

属性啥的有了,具体的Drawable 也有了,要显示的地方调用也是OK了;但是如果没有进行进行具体的位置调整这一切也都没有意义。@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

initDrawableSize();

}

private void initDrawableSize() {

int pLeft = getPaddingLeft();

int pRight = getPaddingRight();

int pTop = getPaddingTop();

int pBottom = getPaddingBottom();

int width = getWidth();

int height = getHeight();

int cWidth = width - pLeft - pRight;

int cHeight = height - pTop - pBottom;

Rect bounds;

if (mMarkerDrawable != null) {

// Size

int markerSize = Math.min(mMarkerSize, Math.min(cWidth, cHeight));

mMarkerDrawable.setBounds(pLeft, pTop,

pLeft + markerSize, pTop + markerSize);

bounds = mMarkerDrawable.getBounds();

} else {

bounds = new Rect(pLeft, pTop, pLeft + cWidth, pTop + cHeight);

}

int halfLineSize = mLineSize >> 1;

int lineLeft = bounds.centerX() - halfLineSize;

if (mBeginLine != null) {

mBeginLine.setBounds(lineLeft, 0, lineLeft + mLineSize, bounds.top);

}

if (mEndLine != null) {

mEndLine.setBounds(lineLeft, bounds.bottom, lineLeft + mLineSize, height);

}

}

initDrawableSize 方法进行具体的运算,而运算的时间点就是当控件的大小改变(onSizeChanged)的时候。

在初始化中采用了一定的投机取巧;这里利用了上内边距与下内边距分别作为上线条与下线条的长度;而线条与中间的标识都采用了水平距中。

其他设置方法public void setLineSize(int lineSize) {

if (mLineSize != lineSize) {

this.mLineSize = lineSize;

initDrawableSize();

invalidate();

}

}

public void setMarkerSize(int markerSize) {

if (this.mMarkerSize != markerSize) {

mMarkerSize = markerSize;

initDrawableSize();

invalidate();

}

}

public void setBeginLine(Drawable beginLine) {

if (this.mBeginLine != beginLine) {

this.mBeginLine = beginLine;

if (mBeginLine != null) {

mBeginLine.setCallback(this);

}

initDrawableSize();

invalidate();

}

}

public void setEndLine(Drawable endLine) {

if (this.mEndLine != endLine) {

this.mEndLine = endLine;

if (mEndLine != null) {

mEndLine.setCallback(this);

}

initDrawableSize();

invalidate();

}

}

public void setMarkerDrawable(Drawable markerDrawable) {

if (this.mMarkerDrawable != markerDrawable) {

this.mMarkerDrawable = markerDrawable;

if (mMarkerDrawable != null) {

mMarkerDrawable.setCallback(this);

}

initDrawableSize();

invalidate();

}

}

在设置中,首先判断是否更改,如果更改那么就更新并重新计算位置;随后刷新界面。到这里,控件差不多准备OK了,其中还有很多可以完善的地方,比如加上快捷设置颜色什么的,也可以加上大小计算的东西。同时还可以加上时间线是水瓶还是垂直等等。在这里就不累赘介绍哪些了。下面来看看如何使用。

使用

XML布局

ITEM布局item_time_line.xml<?xml  version="1.0" encoding="utf-8"?>

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal"

android:paddingLeft="@dimen/lay_16"

android:paddingRight="@dimen/lay_16"

tools:ignore="MissingPrefix">

android:id="@+id/item_time_line_mark"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:paddingBottom="@dimen/lay_16"

android:paddingLeft="@dimen/lay_4"

android:paddingRight="@dimen/lay_4"

android:paddingTop="@dimen/lay_16"

app:beginLine="@color/black_alpha_32"

app:endLine="@color/black_alpha_32"

app:lineSize="2dp"

app:marker="@drawable/ic_timeline_default_marker"

app:markerSize="24dp" />

android:id="@+id/item_time_line_txt"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:paddingBottom="@dimen/lay_16"

android:paddingLeft="@dimen/lay_4"

android:paddingRight="@dimen/lay_4"

android:paddingTop="@dimen/lay_16"

android:textColor="@color/grey_600"

android:textSize="@dimen/font_16" />

在这里我们之间使用顺序布局,左边是TimelIne控件,右边是一个简单的字体控件,具体使用中可以细化一些。 在TImeLine控件中我们的Mark是使用的drawable/ic_timeline_default_marker;这个就是一个简单的圆圈而已;对于自己美化可以使用一张图片代替或者更加复杂的布局;当然上面的线条就更加简单了,就直接使用颜色代替。<?xml  version="1.0" encoding="utf-8"?>

android:shape="oval">

android:width="1dp"

android:color="@color/black_alpha_32" />

主界面XML RecyclerView

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:paddingBottom="@dimen/activity_vertical_margin"

android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"

android:paddingTop="@dimen/activity_vertical_margin"

tools:context=".MainActivity">

android:id="@+id/time_line_recycler"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:clickable="true"

android:fadeScrollbars="true"

android:fadingEdge="none"

android:focusable="true"

android:focusableInTouchMode="true"

android:overScrollMode="never"

android:scrollbarSize="2dp"

android:scrollbarThumbVertical="@color/cyan_500"

android:scrollbars="vertical" />

在这里就是加上了一个RecyclerView 控件在主界面就OK。

Java代码部分

在开始之前先来看看我们的文件具体有些神马。

1440469609114998.pngwidget中就是具体的自定义控件,model是具体的数据模型,adapter部分,这里有一个Recyclerview的adapter文件,以及一个具体的Item TimeLineViewHolder,当然在这里还定义了一个ItemType类,该类用来标示每个Item的类型,比如头部,第一个,普通,最后一个,底部等等。

TimeLineModel.javapackage net.qiujuer.example.timeline.model;

/**

* Created by qiujuer

* on 15/8/23.

*/

public class TimeLineModel {

private String name;

private int age;

public TimeLineModel() {

}

public TimeLineModel(String name, int age) {

this.name = name;

this.age = age;

}

public int getAge() {

return age;

}

public String getName() {

return name;

}

public void setAge(int age) {

this.age = age;

}

public void setName(String name) {

this.name = name;

}

}

一个名字,一个年龄也就OK。

ItemType.javapackage net.qiujuer.example.timeline.adapter;

/**

* Created by qiujuer

* on 15/8/23.

*/

public class ItemType {

public final static int NORMAL = 0;

public final static int HEADER = 1;

public final static int FOOTER = 2;

public final static int START = 4;

public final static int END = 8;

public final static int ATOM = 16;

}

分别定义了几个静态值,分别代表普通、头部、底部、开始、结束、原子;当然其中有些可以不用定义。

TimeLineViewHolder.javapackage net.qiujuer.example.timeline.adapter;

import android.support.v7.widget.RecyclerView;

import android.view.View;

import android.widget.TextView;

import net.qiujuer.example.timeline.R;

import net.qiujuer.example.timeline.model.TimeLineModel;

import net.qiujuer.example.timeline.widget.TimeLineMarker;

/**

* Created by qiujuer

* on 15/8/23.

*/

public class TimeLineViewHolder extends RecyclerView.ViewHolder {

private TextView mName;

public TimeLineViewHolder(View itemView, int type) {

super(itemView);

mName = (TextView) itemView.findViewById(R.id.item_time_line_txt);

TimeLineMarker mMarker = (TimeLineMarker) itemView.findViewById(R.id.item_time_line_mark);

if (type == ItemType.ATOM) {

mMarker.setBeginLine(null);

mMarker.setEndLine(null);

} else if (type == ItemType.START) {

mMarker.setBeginLine(null);

} else if (type == ItemType.END) {

mMarker.setEndLine(null);

}

}

public void setData(TimeLineModel data) {

mName.setText("Name:" + data.getName() + " Age:" + data.getAge());

}

}

该文件为RecyclerView 的Adapter中每个Item需要实现的Holder类。 在该类中,我们在构造函数中需要传入一个根View同时传入一个当然item的状态。 随后使用find….找到控件,在这里我们把TextView保存起来,而TimeLineView找到后直接进行初始化设置。 根据传入的ItemType来判断是否是第一个,最后一个,以及原子;然后设置TimeLineView的属性。 在下面的setData方法中我们显示具体的Model数据。

TimeLineAdapter.java

适配器部分,我们需要做的工作是;根据具体的数据渲染上对应的界面就OK。package net.qiujuer.example.timeline.adapter;

import android.support.v7.widget.RecyclerView;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import net.qiujuer.example.timeline.R;

import net.qiujuer.example.timeline.model.TimeLineModel;

import java.util.List;

/**

* Created by qiujuer

* on 15/8/23.

*/

public class TimeLineAdapter extends RecyclerView.Adapter {

private List mDataSet;

public TimeLineAdapter(List models) {

mDataSet = models;

}

@Override

public int getItemViewType(int position) {

final int size = mDataSet.size() - 1;

if (size == 0)

return ItemType.ATOM;

else if (position == 0)

return ItemType.START;

else if (position == size)

return ItemType.END;

else return ItemType.NORMAL;

}

@Override

public TimeLineViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

// Create a new view.

View v = LayoutInflater.from(viewGroup.getContext())

.inflate(R.layout.item_time_line, viewGroup, false);

return new TimeLineViewHolder(v, viewType);

}

@Override

public void onBindViewHolder(TimeLineViewHolder timeLineViewHolder, int i) {

timeLineViewHolder.setData(mDataSet.get(i));

}

@Override

public int getItemCount() {

return mDataSet.size();

}

}在这里需要着重说一下:我复写了getItemViewType方法;在该方法中我们需要设置对应的Item的类型;在这里传入的是item的坐标,需要返回的是item的具体状态,该状态标示是int类型;在这里我使用的是ItemType的静态属性。

该方法会在调用onCreateViewHolder方法之前调用;而onCreateViewHolder方法中的第二个参数int值也就是从getItemViewType之中来;所以我们可以在这里进行对应的数据状态标示。

而在onCreateViewHolder方法中我们返回一个:TimeLineViewHolder就OK,随后在onBindViewHolder方法中进行数据初始化操作。

MainActivity.java

上面所有都准备好了,下面就进行具体的显示。 在这里就只贴出核心代码了;篇幅也是有些长。private RecyclerView mRecycler;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mRecycler = (RecyclerView) findViewById(R.id.time_line_recycler);

initRecycler();

}

private void initRecycler() {

LinearLayoutManager layoutManager = new LinearLayoutManager(this);

layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

TimeLineAdapter adapter = new TimeLineAdapter(getData());

mRecycler.setLayoutManager(layoutManager);

mRecycler.setAdapter(adapter);

}

private List getData() {

List models = new ArrayList();

models.add(new TimeLineModel("XiaoMing", 21));

models.add(new TimeLineModel("XiaoFang", 20));

models.add(new TimeLineModel("XiaoHua", 25));

models.add(new TimeLineModel("XiaoA", 22));

models.add(new TimeLineModel("XiaoNiu", 23));

return models;

}

在这里就是傻瓜的操作了,流程就是准备好对应的数据,装进Adapter,准备好对应的布局方式,然后都设置到RecyclerView中就OK。

效果

来看看具体的效果:

1440469865127253.png

效果虽然简单,但是也算是五脏具全;其中无非就是控件的自定义。这个自定义是可以扩展的,大家可以扩展为水平方向试试。

代码

写在最后

文章的开始截屏来源于:最近没事儿捣鼓了一个APP[UPMiss],一个简单的生日,纪念日提醒软件;欢迎大家尝鲜。

{UPMiss} 思念你的夏天 下载地址:百度 这个审核有问题,明明没有支付的东西,结果说有支付的SDK存在,不得不说百度的自动审核有很大漏洞。

豌豆荚 新版2.0还在审核中!

======================================================== 作者:qiujuer

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

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

相关文章

android rxjava2 简书,RXJava2学习

什么是RxJava一个可观测的序列来组成异步的、基于事件的程序的库。(简单来说&#xff1a;它就是一个实现异步操作的库)RxJava 好在哪?RxJava 其实就是提供一套异步编程的 API&#xff0c;这套 API 是基于观察者模式的&#xff0c;而且是链式调用的&#xff0c;所以使用 RxJava…

无尽包围html5游戏在线玩,小团体激发潜能小游戏突破自我

缩小包围圈游戏其实是一个不可能完成的任务&#xff0c;但是它会给游戏者带来无尽欢笑&#xff0c;使小组充满活力&#xff0c;让队员们能够自然地进行身体接触和配合&#xff0c;消除害羞和忸怩感&#xff0c;创造融洽的气氛&#xff0c;为后续工作的开展奠定良好基础。可以作…

html5鼠标下拉浮窗固定,【前端技术】vue-floating-menu可拖拽吸附的浮窗菜单

前言正如这个名字&#xff0c;这是一个具有拖拽吸附功能的浮窗菜单&#xff0c;开源项目一个基于 vue 的浮窗组件,可在屏幕内自由拖拽&#xff0c;拖拽后可以根据最后的位置吸附到页面两边&#xff0c;而且可以点击浮窗显示菜单效果如下:遇到的问题总结鼠标移动过快&#xff0c…

html vba 单元格 格式,VBA设置单元格格式之——字体

009 设置单元格格式之字体(文档下载&#xff1a;关注本公众号&#xff0c;发送消息【教程】即可获得)通过VBA对单元格字体进行设置也是比较常用的方式&#xff0c;那么本节内容我们就来学习如何使用VBA对单元格中的字体进行设置。如图所示&#xff0c;字体设置主要有&#xff0…

2021聊城二中高考成绩查询,聊城中考成绩查询时间2021

聊城市2021年中考查分时间大约是6月27日。各普通高中要于7月10日前在校内张榜公布录取考生名单&#xff0c;并签发录取通知书。聊城中考录取时间各普通高中要于7月10日前在校内张榜公布录取考生名单&#xff0c;并签发录取通知书。所有学校均不得违规招收已被其他学校录取的考生…

桂林电子科技大学计算机信息管理专业排名,桂林电子科技大学信息科技学院优势专业排名,2021年桂林电子科技大学信息科技学院最好的专业排名...

桂林电子科技大学优势专业由桂林电子科技大学历届学长学姐实名推荐&#xff1a;1、通信工程 推荐指数: 4.8(156人推荐)2、电子信息工程 推荐指数: 4.6(135人推荐)3、机械设计制造及其自动化 推荐指数: 4.6(114人推荐)4、电气工程及其自动化 推荐指数: 4.5(93人推荐)5、测控技术…

计算机网络五层模型以及数据单元,计算机网络OSI模型、TCP/IP模型与5G协议

一、 OSI参考模型国际标准化组织(ISO)在1984年颁布了开放系统互连参考模型(OSI)&#xff0c;这是一个开放式的体系结构&#xff0c;将网络分为了七层。这七层分别是应用层、表示层、会话层、传输层、网络层、数据链路层和物理层。1.1 七层模型的功能分层功能应用层网络服务与最…

台式机计算机怎么分割,编辑手把手教程 如何给电脑硬盘分区

1找到磁盘管理工具目前主流的电脑&#xff0c;都预装了正版Win7操作系统&#xff0c;相信就算没有安装系统&#xff0c;朋友们在买到新电脑后的第一件事就是安装Windows操作系统。虽然Win8操作系统即将面世&#xff0c;但Win7操作系统的市场占有率已跟经典的Windows XP操作系统…

银行柜员网申计算机水平要求高吗,银行网申没通过,是因为你水平差吗?

原标题&#xff1a;银行网申没通过&#xff0c;是因为你水平差吗&#xff1f;近段时间&#xff0c;各进银行陆续开设网申通道&#xff0c;各位憧憬进入到银行工作的学员也在紧张的网申材料准备中。根据往年的经验来看&#xff0c;会有学员对小编吐槽“同学都收到网申通过的通知…

辽宁沈阳计算机学校王斯琪,青春正好,理所当“燃”——沈阳万合技校开展2020-2021年度春季学期跳大绳比赛...

原标题&#xff1a;青春正好&#xff0c;理所当“燃”——沈阳万合技校开展2020-2021年度春季学期跳大绳比赛辽宁万合职业教育集团Liaoning Wanhe Vocational Education Group沈阳万合职业技术学校Shenyang Wanhe vocational and technical school跳跃奔跑的身影&#xff0c;爽…

win10计算机系统优化设置,win10系统优化系统的详细办法

作为大多数用户都使用的win10系统&#xff0c;如果发生对win10系统优化系统进行设置情况&#xff0c;会让人束手无策&#xff0c;那么win10系统优化系统是怎么设置的呢&#xff1f;如果有朋友想对win10系统优化系统进行设置的话&#xff0c;按照1、右键点击“此电脑”&#xff…

arm放弃服务器芯片,ARM溃败:Applied Micro拆分ARM架构服务器芯片业务

上月下旬通信芯片厂商MACOM达成最终协议以约7.7亿美元收购Applied Micro&#xff0c;日前则已决定只留下后者的高速载波和数据中心连网芯片业务&#xff0c;分拆它的ARM架构服务器芯片业务&#xff0c;这对ARM在服务器芯片市场造成了重击&#xff0c;对于Intel来说则是重大喜讯…

计算机硬盘写入错误怎么办,电脑提示缓存文件写入失败

非正常电脑关引起的&#xff1a;如果是非正常关电脑引起的写入缓存失败&#xff0c;那就在【运行】中输入【CHKDSK 盘符】。系统错误&#xff1a;1&#xff0c;打开我的电脑&#xff0c;打开本地磁盘属性&#xff0c;在弹出的对话框中选择【工具】--【开始检查】&#xff0c;2&…

win2008验证服务器错误,win2008dcdiag检测出的错误,求解决方法

win2008dcdiag检测出的错误目录服务器诊断正在执行初始化设置:正在尝试查找主服务器...主服务器 SPS003* 已识别的 AD 林。已完成收集初始化信息。正在进行所需的初始化测试正在测试服务器: Default-First-Site-Name\SPS003开始测试: Connectivity......................... S…

ajax 405报错,使用ajax请求时发生随机HTTP错误405

我收到HTTP错误405动词不允许。由于有时代码有效&#xff0c;并且有时会抛出http 405错误&#xff0c;所以我需要了解这是编程问题还是服务器配置问题。我用jQuery使用ajax。我在这里浏览了所有相关的帖子&#xff0c;并尝试了与代码相关的所有推荐选项。请帮忙。使用ajax请求时…

我的世界服务器修改末地难度,涨姿势啦!我的世界老司机带你解锁进入末地的高难度姿势!...

我的世界中国版从发布至今已经有八年的时光了&#xff0c;很多玩家从一开始就陪着我的世界成长&#xff0c;可以说是看着它长大的了。如果你是我的世界的忠实玩家&#xff0c;那么你肯定知道进入末地的唯一渠道就是末地门啦&#xff0c;但是坏坏今天来就是来告诉你们进入大名鼎…

Vue-cli项目中mockjs + axios实现前后端分离代码demo(清晰易懂)

基础准备&#xff1a;1、npm安装vue-cli脚手架后&#xff0c;通过命令“ vue init webpack 项目名 ”来创建项目&#xff1b;2、了解mockjs&#xff0c;能拦截ajax请求&#xff0c;返回模拟的响应数据&#xff0c;实现前后端分离&#xff1b;&#xff08;详细学习网址&#xff…

绘制扇形的多种方式,包括border-radius、clip裁剪显示、canvas原点变换等方式的详细理解及demo

对clip的理解&#xff1a; clip是对使用了该样式的元素进行裁剪显示。使用方法是rect (top, right, bottom, left) 其中参数top代表显示的区域上边界离该元素顶部border-top相对距离&#xff0c;依此分别是右边界离该元素左侧border-left相对距离。参数top和left取值auto时候代…

CSS文字或元素的水平垂直居中多种方式(简单明了)

前言&#xff1a;水平居中&#xff0c;我们可以很容易想到使用text-align实现文字水平居中&#xff0c;使用margin:0px auto;可以实现元素水平居中&#xff1b;所以重点将是怎么实现文字和元素的垂直居中&#xff1f;&#xff1f; --- 本文将通过举栗子说明各种解决方式&#x…

Vue-cli 项目打包布署(简单清晰)

第一步&#xff1a;项目打包前更改项目config配置 打开项目的 config>index.js文件修改build对象的assetsPublicPath: 属性值为 ./ 如下 第二步&#xff1a;对vue-cli项目进行打包 在运行窗口输入cmd后打开命令窗口&#xff0c;在项目文件下输入npm run build命令 如下&…