SKU管理模块 开发

  • 先完成静态组件
### Sku.index.vue

<template>
  <div>
    <el-table style="width: 100%" border >
      <el-table-column type="index" label="序号" width="80px" align="center">
      </el-table-column>

      <el-table-column prop="prop" label="名称" width="width">
      </el-table-column>

      <el-table-column prop="prop" label="描述" width="width">
      </el-table-column>

      <el-table-column prop="prop" label="默认图片" width="110">
      </el-table-column>

      <el-table-column prop="prop" label="重量" width="80">
      </el-table-column>

      <el-table-column prop="prop" label="价格" width="80">
      </el-table-column>

      <el-table-column prop="prop" label="操作" width="width">
      </el-table-column>

    </el-table>

    <!--
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      page-sizes: 选择器,每页选择显示几条数据,[3,5,10]
      page-count: 页码数量,必须奇数
      layout: 组件布局
    -->
    <el-pagination style="margin-top: 20px;textAlign:center" :current-page="page" :page-size="limit"
      :page-sizes="[3,5,10]" :page-count="7" :total="total" layout="prev,pager,next,jumper,->,sizes,total">
    </el-pagination>
  </div>
</template>

<script>
  export default {
    name:'Sku'
  }
</script>

<style>
</style>

  • 配置请求并存储后端返回的数据
### product.sku.js
......
export const reqSkuList = (page,limit)=>request({url:`/admin/product/list/${page}/${limit}`,method:'get'})

### Sku.index.vue
......
<script>
  export default {
    name:'Sku',
    data(){
      return {
        // 分页相关
        page:1,
        limit:10,
        total:0,
        // 存储SKU列表数据
        records:[]
      }
    },
    methods:{

      async getSkuList(){
        const {page,limit} = this;
        let res = await this.$API.sku.reqSkuList(page,limit)
        if(res.code == 200){
          this.records = res.data.records
          this.total = res.data.total
        }
      }
    },
    mounted(){
      this.getSkuList() // 挂载完毕即发请求
    },
  }
</script>
  • 渲染数据
### Sku.index.vue

<template>
  <div>
  	<!--数据源:data-->
    <el-table style="width: 100%" border :data="records">
      <el-table-column type="index" label="序号" width="80px" align="center">
      </el-table-column>
	  <!--渲染数据-->
      <el-table-column prop="skuName" label="名称" width="width">
      </el-table-column>

      <el-table-column prop="skuDesc" label="描述" width="width">
      </el-table-column>

      <el-table-column label="默认图片" width="110">
        <template slot-scope="{row,$index}">
          <img :src="row.skuDefaultImg" style="width: 80px;height: 80px;">
        </template>
      </el-table-column>

      <el-table-column prop="weight" label="重量" width="80">
      </el-table-column>

      <el-table-column prop="price" label="价格" width="80">
      </el-table-column>

      <el-table-column prop="prop" label="操作" width="width">
        <template slot-scope="{row,$index}">
          <el-button type="success" icon="el-icon-sort-down" size="mini"></el-button>
          <el-button type="success" icon="el-icon-sort-up" size="mini"></el-button>
          <el-button type="primary" icon="el-icon-edit" size="mini"></el-button>
          <el-button type="info" icon="el-icon-info" size="mini"></el-button>
          <el-button type="danger" icon="el-icon-delete" size="mini"></el-button>
        </template>
      </el-table-column>
      
    </el-table>
	<!--绑定页码事件和每页展示数据量事件-->
    <el-pagination style="margin-top: 20px;textAlign:center" :current-page="page" :page-size="limit"
      :page-sizes="[3,5,10]" :page-count="7" :total="total" layout="prev,pager,next,jumper,->,sizes,total"
      @current-change="getSkuList" @size-change="handleSizeChange">
    </el-pagination>
  </div>
</template>

<script>
  export default {
    name:'Sku',
    ......
    methods:{

      async getSkuList(pages=1){
       ......
      },
      // 每页展示多少条数据
      handleSizeChange(limit){
        this.limit = limit
        this.getSkuList()
      }
    },
   ......
  }
</script>

SKU商品的"上架"与"下架" 功能实现

  • 结构互斥,是否上架由isSale字段来决定
......
<!--互斥-->
<el-button type="success" icon="el-icon-sort-down" size="mini" v-if="row.isSale==0"></el-button>
<el-button type="success" icon="el-icon-sort-up" size="mini" v-else></el-button>
  • 发请求通知后端,用户的动作(是'上架'还是'下架')
### product.sku.js
......
// 通知SKU商品是否'上架'
export const reqCancel = (skuId)=>request({url:`/admin/product/cancelSale/${skuId}`,method:'get'})
  • 绑定点击事件并书写逻辑
### Sku.index.vue
......
<el-table-column prop="prop" label="操作" width="width">
	<template slot-scope="{row,$index}">
	  <!--绑定两个点击事件-->
	  <el-button type="success" icon="el-icon-sort-down" size="mini" v-if="row.isSale==0" @click="sale(row)"></el-button>
	  <el-button type="success" icon="el-icon-sort-up" size="mini" v-else @click="cancel(row)"></el-button>
	  ......
	</template>
</el-table-column>
......
async sale(sku){
	let res = await this.$API.sku.reqCancel(sku.id)
	if(res.code == 200){
	  sku.isSale = 1;
	  this.$message({type:'success',message:'上架成功'})
	}
},
async cancel(sku){
	let res = await this.$API.sku.reqCancel(sku.id)
	if(res.code == 200){
	  sku.isSale = 0;
	  this.$message({type:'success',message:'下架成功'})
	}
}

获取SKU详情 功能实现

  • 配置请求
### product.sku.js
......
// 获取SKU详情
export const reqSkuById = (skuId)=>request({url:`/admin/product/getSkuById/${skuId}`,method:'get'})
  • 搞定静态组件
### Sku.index.vue
......
 <el-pagination> 
 ......
</el-pagination>

<!--SKU详情抽屉效果-->
<el-drawer
  :visible.sync="drawer"
  :direction="direction"
  :show-close="false"
  size="50%"
  >
  <el-row>
	<el-col :span="5">名称</el-col>
	<el-col :span="16">sku</el-col>
  </el-row>

  <el-row>
	<el-col :span="5">名称</el-col>
	<el-col :span="16">sku</el-col>
  </el-row>

  <el-row>
	<el-col :span="5">名称</el-col>
	<el-col :span="16">sku</el-col>
  </el-row>

  <el-row>
	<el-col :span="5">名称</el-col>
	<el-col :span="16">sku</el-col>
  </el-row>

  <el-row>
	<el-col :span="5">名称</el-col>
	<el-col :span="16">sku</el-col>
  </el-row>

</el-drawer>
......
<script>
  export default {
    name:'Sku',
    data(){
      return {
       ......
        // 抽屉效果
        drawer: false,
        direction: 'rtl',
      }
    },
    methods:{
     ......
      async getSkuInfo(sku){
		// 若把逻辑写在"发请求"后面,会造成抽屉效果'延迟',故放到前面
        this.drawer = true; // 抽屉展示SKU详情
        let res= await this.$API.sku.reqSkuById(sku.id)
        ......
      },
    },
  }
</script>
  • 渲染数据
### Sku.index.vue
......
<!--SKU详情抽屉效果-->
<el-drawer
  :visible.sync="drawer"
  :direction="direction"
  :show-close="false"
  size="50%"
  >
  <el-row>
	<el-col :span="5">名称</el-col>
	<el-col :span="16">{{skuInfo.skuName}}</el-col>
  </el-row>

  <el-row>
	<el-col :span="5">描述</el-col>
	<el-col :span="16">{{skuInfo.skuDesc}}</el-col>
  </el-row>

  <el-row>
	<el-col :span="5">价格</el-col>
	<el-col :span="16">{{skuInfo.price}}</el-col>
  </el-row>

  <el-row>
	<el-col :span="5">平台属性</el-col>
	<el-col :span="16">
	  <!--使用template插入tag标签-->
	  <template>
		<el-tag type="success" v-for="(attr,index) in skuInfo.skuAttrValueList" :key="attr.id" style="margin-right:10px">{{attr.attrId}}-{{attr.valueId}}</el-tag>
	  </template>
	</el-col>
  </el-row>

  <el-row>
	<el-col :span="5">商品图片</el-col>
	<el-col :span="16">
	  <!--轮播图(也叫"走马灯")-->	
	  <el-carousel height="150px">
		<el-carousel-item v-for="item in skuInfo.skuImageList" :key="item.id">
		  <img :src="item.imgUrl" alt="">
		</el-carousel-item>
	  </el-carousel>
	</el-col>
  </el-row>

</el-drawer>
......
<script>
  export default {
    name:'Sku',
    data(){
      return {
        ......
        drawer: false,
        direction: 'rtl',
      }
    },
    ......
  }
</script>

<style scoped>
  .el-row .el-col-5 {
    font-size: 18px;
    text-align: right;
  }
  .el-col {
    margin: 10px 10px;
  }
</style>

<style>
  /* 组件自带样式 */
  .el-carousel__item h3 {
      color: #475669;
      font-size: 14px;
      opacity: 0.75;
      line-height: 150px;
      margin: 0;
    }

    .el-carousel__item:nth-child(2n) {
       background-color: #99a9bf;
    }

    .el-carousel__item:nth-child(2n+1) {
       background-color: #d3dce6;
    }
     /* 自定义轮播图小按钮的样式(原生的太丑) */
    .el-carousel__button {
      width: 10px;
      height: 10px;
      background: red;
      border-radius: 50%;
    }
</style>

深度选择器

  • scoped属性: 只对当前的组件样式有用
  • 底层原理: 给当前组件添加上了一个data-v-xxxx自定义属性,vue通过属性选择器,给元素添加上样式
- h3[data-v-78b7sd7f790]
  • 子组件根标签(拥有父组件当中的自定义属性)
- 若子组件的根节点,和父组件中书写的样式相同,也会添加上相应的样式
- 通俗理解: 此时父组件中使用了"scoped",子组件也会生效
  • 注意事项: 如果父组件的样式(scoped),此时还想影响子组件的样式,这种情况可以使用深度选择器

  • 深度选择器可以实现样式穿透

- 原生CSS: >>>

	<style scoped>
		>>>h3{
			color:red;
		}
	</style>

- less: /deep/
- scss: ::v-deep
  • 应用到项目中,可以这么写
### Sku,index.vue
......
<style scoped>
  .el-row .el-col-5 {
    font-size: 18px;
    text-align: right;
  }
  .el-col {
    margin: 10px 10px;
  }
  /* 样式穿透 */
  >>>.el-carousel__button {
    width: 10px;
    height: 10px;
    background: red;
    border-radius: 50%;
  }
</style>

<style>
  ......
    
    /* .el-carousel__button {
      width: 10px;
      height: 10px;
      background: red;
      border-radius: 50%;
    } */

</style>

canvas(画布)

  • 基本使用
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			* {
				margin: 0;
				padding: 0;
			}
			/*画布效果*/
			canvas {
				border: 1px solid red;
			}
		</style>
	</head>
	<body>
		<canvas></canvas>
	</body>
</html>
- 默认宽度和高度是 300*150
- 浏览器认为canvas标签是一张图片
- 添加文本 || 子节点 没有任何意义
- 该标签的宽度和高度务必通过 width||height设置

	<body>
		<canvas width="600" height="400"></canvas>
	</body>
  • 绘制线段并闭合图形(三角形)
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			* {
				margin: 0;
				padding: 0;
			}
			canvas {
				border: 1px solid red;
			}
		</style>
	</head>
	<body>
		<canvas width="600" height="400"></canvas>
	</body>
</html>
<script>
	let canvas = document.querySelector('canvas') // 获取cavas对象
	let ctx = canvas.getContext('2d') // 获取画笔
	ctx.moveTo(100,100) // 设置起点
	ctx.lineTo(100,200) // 设置其他点
	ctx.lineTo(200,100)
	ctx.closePath() // 闭合路径
	ctx.stroke() // 开始绘图
</script>
  • 配置线段的颜色,填充区域
<script>
	let canvas = document.querySelector('canvas')
	let ctx = canvas.getContext('2d')
	ctx.moveTo(100,100)
	ctx.lineTo(100,200)
	ctx.lineTo(200,100)
	
	ctx.fillStyle = "red"
	ctx.fill() // 填充
	ctx.strokeStyle = "purple" // 线段颜色
	ctx.lineWidth = 2
	
	ctx.closePath()
	ctx.stroke()
</script>
  • 绘制矩形
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			* {
				margin: 0;
				padding: 0;
			}
			canvas {
				border: 1px solid red;
			}
		</style>
	</head>
	<body>
		<canvas width="600" height="400"></canvas>
	</body>
</html>
<script>
	let canvas = document.querySelector('canvas')
	let ctx = canvas.getContext('2d')
	// (x,y,宽度,高度)
	// 注意: 使用strokeRect无法填充图形并设置样式(局限性大)
	ctx.strokeRect(100,200,100,200)
</script>
  • 绘制可以填充样式的矩形
......
<script>
	let canvas = document.querySelector('canvas')
	let ctx = canvas.getContext('2d')
	ctx.fillStyle = 'skyblue' // 设置样式
	ctx.fill()
	ctx.fillRect(300,200,100,200)
</script>
  • 绘制圆形
......
<script>
	let canvas = document.querySelector('canvas')
	let ctx = canvas.getContext('2d')
	// 绘制圆形
	ctx.beginPath();
	// 参数(x,y(圆心位置),半径,起始弧度,结束弧度,顺/逆时针)
	ctx.arc(100,100,50,0,2*Math.PI,true)
	ctx.fillStyle = 'skyblue'
	ctx.fill()
	ctx.stroke()
</script>

注意事项: 再次强调

- canvas的宽度和高度,一定不能通过css去设置,否则绘图的时候,会出现各种不可思议的问题
  • 清除画布(清除部分 && 清除全部)
let canvas = document.querySelector('canvas')
	let ctx = canvas.getContext('2d')
	ctx.fillStyle = 'skyblue'
	ctx.fill()
	ctx.fillRect(300,200,100,200)
	// 清除部分画布内容
	// ctx.clearRect(300,200,50,100)
	// 清除所有画布内容
	ctx.clearRect(0,0,600,400)
  • 绘制文字
<script>
	let canvas = document.querySelector('canvas')
	let ctx = canvas.getContext('2d')
	ctx.font = "30px 微软雅黑" // 设置大小,字体,颜色
	ctx.fillStyle = 'red'
	ctx.fillText('数据可视化',50,50) // 绘制文字
</script>

案例: 绘制矩形柱状图

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			* {
				margin: 0;
				padding: 0;
			}
			canvas {
				border: 1px solid red;
			}
		</style>
	</head>
	<body>
		<canvas width="800" height="420"></canvas>
	</body>
</html>
<script>
	let canvas = document.querySelector('canvas')
	let ctx = canvas.getContext('2d')
	
	ctx.font = "16px 微软雅黑"; // 绘制文字
	ctx.fillText('数据可视化',50,80)
	
	ctx.moveTo(100,100) // 绘制Y轴
	ctx.lineTo(100,400)
	
	ctx.lineTo(700,400) // 绘制X轴
	ctx.stroke() // 作画
	
	// 绘制横线
	ctx.moveTo(100,100);
	ctx.lineTo(700,100) // 绘制最上层的横线
	ctx.fillText('150',70,110) // Y轴数值
	
	ctx.moveTo(100,160);
	ctx.lineTo(700,160) // 绘制次上层的横线
	ctx.fillText('120',70,170) // Y轴数值
	
	ctx.moveTo(100,220);
	ctx.lineTo(700,220) // 绘制第三层的横线
	ctx.fillText('90',70,230) // Y轴数值
	
	ctx.moveTo(100,280);
	ctx.lineTo(700,280) // 绘制第四层的横线
	ctx.fillText('60',70,290) // Y轴数值
	
	ctx.moveTo(100,340);
	ctx.lineTo(700,340) // 绘制第五层的横线
	ctx.fillText('30',70,350) // Y轴数值
	ctx.stroke()
	
	// 绘制水平轴底部的线段
	ctx.moveTo(250,400); // 最近的线段
	ctx.lineTo(250,410)
	// ctx.stroke() 
	
	ctx.moveTo(400,400); // 第二个线段
	ctx.lineTo(400,410)
	
	ctx.moveTo(550,400); // 第三个线段
	ctx.lineTo(550,410)
	ctx.stroke()
	
	// 绘制底部文字
	ctx.fillText('食品',170,415)
	ctx.fillText('数码',310,415)
	ctx.fillText('服饰',450,415)
	ctx.fillText('箱包',600,415)
	ctx.stroke()
	
	// 绘制矩形
	ctx.fillStyle = 'red'
	ctx.fillRect(120,200,100,200)
	
	
	
</script>

svg

  • 矢量图
  • 通俗理解: 封装度更高的canvas
### demo演示: 画各种图形

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			* {
				margin: 0;
				padding: 0;
			}
			.box {
				width: 800px;
				height: 800px;
			}
		</style>
	</head>
	<body>
		<svg class="box">
			<!--x1,y1是第一个点的左边,以此类推-->
			<line x1="100" y2="100" x2="200" y2="200" stroke="red"></line>
			<!--绘制折线-->
			<polyline points="300 300,50 100,120 400,20,20" fill-opacity="0" stroke="cyan"></polyline>
			<!--绘制矩形-->
			<rect x="400" y="400" width="150" height="50" fill="pink"></rect>
			<!--绘制圆形-->
			<circle cx="370" cy="95" r="50" style="stroke:cyan;fill:none"></circle>
			<!--绘制椭圆-->
			<ellipse cx="500" cy="500" rx="100" ry="50" style="fill:black"></ellipse>
			<!--绘制多边形-->
			<polygon points="600 100,300 400,750 100" stroke="red" fill-opacity="0"></polygon>
			<!-- 绘制任意图形 -->
			<path fill-opacity="0" stroke="skyblue" d="
			  M 10  10
			  L 20 400
			  L 30 120
			  L 40 66
			  L 50 99
			  L 60 120
			  L 70 99
			  Z
			"></path>
			
		</svg>
	</body>
</html>
......

echarts

  • 准备工作
- 引入js依赖包
- 准备容器
- 创建echarts实例
- 配置项

- 注意事项: 若有多张表图,就创建多个容器,实例以及配置项即可
  • demo演示: 柱状图
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<!-- 引入echarts依赖包 -->
		<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.js"></script>
		<style>
			* {
				margin: 0;
				padding: 0;
			}
			div {
				width: 800px;
				height: 400px;
			}
		</style>
	</head>
	<body>
		<!--准备容器-->
		<div></div>
	</body>
</html>
<script>
	let dom = document.querySelector('div') // 获取dom节点
	let mycharts = echarts.init(dom) // 初始化实例
	mycharts.setOption({ // 开始配置
		title:{
			text:'数据可视化',
			subtext:'echarts基本使用'
		},
		xAxis:{
			data:['飞机','大炮','轮船','自行车']
		},
		yAxis:{
			axisLine:{show:true}, // 展示y轴数值
			axisTick:{show:true} // 展示y轴刻度
		},
		series:{
			type:"bar", // 柱状图
			data:[10,20,30,40],
			color:"red"
		}
	})
</script>
  • 展示多个图表: 柱状图折线图展示
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<!-- 引入echarts依赖包 -->
		<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.js"></script>
		<style>
			* {
				margin: 0;
				padding: 0;
			}
			div {
				width: 800px;
				height: 400px;
			}
		</style>
	</head>
	<body>
		<div class="box1"></div>
		<div class="box2"></div>
	</body>
</html>
<script>
	let dom1 = document.querySelector('.box1')
	let dom2 = document.querySelector('.box2')
	let mycharts1 = echarts.init(dom1)
	let mycharts2 = echarts.init(dom2)
	
	mycharts1.setOption({
		title:{
			text:'数据可视化',
			subtext:'echarts基本使用'
		},
		xAxis:{
			data:['飞机','大炮','轮船','自行车']
		},
		yAxis:{
			axisLine:{show:true},
			axisTick:{show:true}
		},
		series:{
			type:"bar",
			data:[10,20,30,40],
			color:"red"
		}
	});
	
	mycharts2.setOption({
		title:{
			text:'折线图',
			left:"center",
			textStyle:{
				color:'red'
			},
			subtext:'echarts基本使用',
			subtextStyle:{
				color:'cyan'
			}
		},
		xAxis:{
			data:['星期一','星期二','星期三','星期四','星期五','星期六','星期日']
		},
		yAxis:{},
		series:{
			type:"line",
			data:[10,20,15,44,2,19,100],
			color:"skublue"
		}
	})
</script>
  • 一个容器内,显示多张图表: series变成`list``,包裹一个个配置项即可
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<!-- 引入echarts依赖包 -->
		<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.js"></script>
		<style>
			* {
				margin: 0;
				padding: 0;
			}
			div {
				width: 800px;
				height: 400px;
			}
		</style>
	</head>
	<body>
		<div class="box1"></div>
		<div class="box2"></div>
	</body>
</html>
<script>
	let dom1 = document.querySelector('.box1')
	// let dom2 = document.querySelector('.box2')
	let mycharts1 = echarts.init(dom1)
	// let mycharts2 = echarts.init(dom2)
	
	mycharts1.setOption({
		title:{
			text:'数据可视化',
			subtext:'echarts基本使用'
		},
		xAxis:{
			data:['飞机','大炮','轮船','自行车']
		},
		yAxis:{
			axisLine:{show:true},
			axisTick:{show:true}
		},
		series:[
			{
				type:"bar", // 柱状图
				data:[10,20,30,40],
				color:"red"
			},
			{
				type:"line", // 折线图
				data:[10,20,30,40],
				color:"pink"
			},
			{
				type:"pie", // 饼状图
				data:[
					{name:'x',value:10},
					{name:'y',value:20},
					{name:'z',value:30},
					{name:'t',value:40},
				],
				width:150,
				height:150,
				left:150,
				top:100,
				radius:25,
			}
		]
	});
	
</script>

dataset属性介绍

  • 通俗理解: 把原来分散在series的数据,集中放到一起,统一管理(方便组件的复用)
- 之前的方式
    series:[
                {
                    type:"bar",
                    data:[10,20,30,40], // 分散的数据
                    color:"red"
                },
                {
                    type:"line",
                    data:[10,20,30,40], // 分散的数据
                    color:"pink"
                },
                {
                    type:"pie",
                    data:[ // 分散的数据
                        {name:'x',value:10},
                        {name:'y',value:20},
                        {name:'z',value:30},
                        {name:'t',value:40},
                    ],
                    width:150,
                    height:150,
                    left:150,
                    top:100,
                    radius:25
                }
            ]
            
- 现在的方式

	<script>
     ......
     let data = [ // 把数据集放入dataset即可
         ["衣服",10,22,'x',10],
         ["直播",12,55,'y',60],
         ["游戏",16,44,'z',50],
         ["电影",19,32,'t',70],
     ]

     mycharts.setOption({
           dataset:{
              //数据源
              source:data
           },
  • 注意事项: 数据的定义方式,必须是一个二维数组或者对象数组(即数组里面包裹一个个对象)
  • demo示例
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 引入echarts依赖包 -->
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.js"></script>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        div{
            width: 800px;
            height: 400px;
        }
    </style>
</head>
<body>
     <div></div>
</body>
</html>
<script>
     let dom = document.querySelector('div');
     let mycharts = echarts.init(dom);
     //数据集
     let data = [
		 // X轴数据 Y轴数据(柱状) Y轴数据(折线) 饼状数据
         ["衣服",10,10,'x',10],
         ["直播",20,20,'y',20],
         ["游戏",30,30,'z',30],
         ["电影",40,40,'t',40],
     ]
     
     mycharts.setOption({
           //设置数据集
           dataset:{
              //数据源
              source:data
           },
          
           title:{
              
              text:'数据可视化',
       
              subtext:"echarts基本使用",
            
              textStyle:{
                  color:'cyan'
              },
              
              left:'center'
           },
           //x轴的配置项
           xAxis:{
               
               data:["衣服",'直播','游戏','电影']
           },
          
           yAxis:{
              
               axisLine:{
                   show:true
               },
              
               axisTick:{
                   show:true
               }
           },
           
           series:[
            //柱状图    
                { 
                   
                    type:"bar",
                    
                    // data:[10,20,30,40],
                    color:'red',
                    encode:{ // 映射维度为1的数据到y轴
                         y:1
                    }
                }
                ,
                // 折线图
                {
                    type:'line',
                    // data:[10,20,30,40],
                    color:'pink',
                    encode:{ // 映射维度为2的数据到y轴
                         y:2
                    }
                },
                //饼图
                {
                    type:'pie',
                
                    // data:[{name:'x',value:10},{name:'y',value:20},{name:'z',value:30},{name:'t',value:40}],
                  
                    width:250,
                    height:250,
                   
                    left:150,
                    top:100,
                    
                    radius:25,
                     encode:{ // 映射数据集
                         //饼图旁边的文字
                         itemName:3, // 映射维度为3和4 key-value 键值对
                         value:4
                     }
                }
           ]
     });
</script>

Echarts组件

  • 除绘图之外的部分,都可以认为是组件
- xAxis(X轴)
- yAxis(Y轴)
- grid(直角坐标系底板)
  • demo环境搭建: 简单展示柱状图折线图
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>Document</title>
		<!-- 引入echarts依赖包 -->
		<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.js"></script>
		<style>
			* {
				margin: 0;
				padding: 0;
			}

			.box {
				width: 100%;
				height: 400px;
				border: 1px solid black;
			}
		</style>
	</head>
	<body>
		
		<div class="box"></div>
	</body>
</html>
<script>
	
	let dom = document.querySelector('div');
	
	let mycharts = echarts.init(dom);
	
	mycharts.setOption({
		
		
		title: {
			
			text: '数据可视化',
		},
		
		xAxis: {
			
			data: ["衣服", '直播', '游戏', '电影']
		},
		
		yAxis: {},
		
		series: [
			//柱状图    
			{
				
				type: "bar",
			
				data:[10,20,30,40],
				
			},
			// 折线图
			{
				type: 'line',
				data:[20,30,40,50],
				
			},
		]
	});

</script>
  • 添加几个功能组件
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
   
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .box {
            width: 100%;
            height: 400px;
            /* border: 1px solid black; */
        }
    </style>
</head>

<body>
   
    <div class="box"></div>
</body>

</html>
<script>
    
    let dom = document.querySelector('.box');
 
    let mycharts = echarts.init(dom);
   
    mycharts.setOption({
        dataZoom: {}, // 数据滑动条变焦组件
     
        title: {
            text: "echarts组件"
        },
        xAxis: {
            data: ['游戏', '电影', "直播", '娱乐']
        },
        yAxis: {},
        series: [
            {
                name: "柱状图",
                type: "bar",
                data: [20, 30, 40, 50]
            }
            ,
            {
                name: "折线图",
                type: 'line',
                data: [30, 40, 50, 60]
            }
        ]
        ,
        //提示组件
        tooltip: {
            //提示框文字的颜色
            textStyle: {
                color: 'red'
            }
        },
        //图表切换组件
        legend: {
            data: ['柱状图', '折线图']
        },
        //工具栏组件
        toolbox: {
            show: true,
            feature: {
                saveAsImage: {},
                dataZoom: {
                    yAxisIndex: "none"
                },
                dataView: {
                    readOnly: false
                },
                magicType: {
                    type: ["line", "bar"]
                },
                restore: {},
            }
        },
        //调整图标布局(使图表全屏展示)
        grid: {
            left: 30,
            right: 0,
        }
    })
</script>

Echarts基本概念之坐标系

  • 一个坐标系可能由多个组件写作而成,以最常见的直角坐标系举例
- xAxis
- yAxis
- grid(底板)

- xAxis和yAxis 被 grid 自动引用并组织起来,共同工作
  • demo举例: 散点图
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 引入echarts依赖包 -->
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        div {
            width: 100%;
            height: 400px;
        }
    </style>
</head>

<body>
   
    <div></div>
</body>

</html>
<script>
   
    let dom = document.querySelector('div');
    
    let mycharts = echarts.init(dom);
    //一个坐标系:散点图
    mycharts.setOption({
        /
        title: {
            text: "一个坐标系"
        }
        ,
        //x轴
        xAxis: {
             type:'category' // 映射10,13,50....
        },
        yAxis: {},
        //散点图
        series: [
            {
                type: "scatter",
                //散点图的数据
                data: [
                    [10, 20],
                    [13, 66],
                    [50, 9],
                    [44, 22],
                    [15, 10]
                ]
            }
        ]
    });
</script>

首页图表实现

  • 先搞定静态组件
### dashboard新建子组件
### Card.index.vue
<template>
  <div>
    我是顶部显示的card组件
    <Detail></Detail>
  </div>
</template>

<script>
  import Detail from './Detail'
  export default {
    name:'',
    components:{
      Detail
    }
  }
</script>
......

### dashboard注册
<template>
  <div>
    <Card></Card>
  </div>
</template>

<script>

import Card from './Card'

export default {
  name: 'Dashboard',
  components:{
    Card
  },
}
</script>

<style lang="scss" scoped>
.dashboard {
  &-container {
    margin: 30px;
  }
  &-text {
    font-size: 30px;
    line-height: 46px;
  }
}
</style>


### Card新建子组件Detail(需展示四个)
### Detail.index.vue
<template>
  <div>
    <!--把每块区域拆成4个部分-->
    <div class="card-header">头部地方</div>
    <div class="card-content">内容区域</div>
    <div class="card-charts">图标区域</div>
    <div class="card-footer">底部</div>
  </div>
</template>

<script>
  export default {
    name:''
  }
</script>
......


  • 搞定布局
### Card.index.vue

<template>
  <div>
    <el-row :gutter="10">
      <!--总共24个空间-->
      <!--每6个空间插入一个'卡片组件',用来包裹'Detail组件'-->
      <el-col :span="6">
        <el-card>
          <Detail></Detail>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card>
          <Detail></Detail>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card>
          <Detail></Detail>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card>
          <Detail></Detail>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>
......


  • 所谓插槽
    • 子组件留坑
    • 父组件填坑
    • 用途: 复用子组件的时候,遇到结构不一致的时候,子组件预设插槽,由父组件根据插槽渲染不同的结构,传值即可
### 子组件
<template>
  <div>
    <div class="card-header">
      ......
    </div>
    <div class="card-charts">
      <!--留坑-->
      <slot name="charts">
		
      </slot>
    </div>
    
### 父组件
<el-card>
  <Detail title="总销售额" count=" ¥ 12306">
	
	<!--占坑-->
	<template slot="charts">
	  <span>周同比 &nbsp;&nbsp;56.67%</span>
	  <span>周同比 &nbsp;&nbsp;19.96%</span>
	</template>

  </Detail>
</el-card>
  
  • 完成其他静态结构
### Card.index.vue
<template>
  <div>
    <el-row :gutter="10">
      <!--总共24个空间-->
      <el-col :span="6">
        <el-card>
          <Detail title="总销售额" count=" ¥ 12306">
            <!--响应子组件charts插槽,插入自定义的结构-->
            <template slot="charts">
              <span>周同比 &nbsp;&nbsp;56.67%</span>
              <!--插入矢量图-->
              <svg t="1692935095365" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5389" width="16" height="16"><path d="M698.7 480.9v429.5c0 54.8-44.5 99.3-99.3 99.3H434c-54.8 0-99.3-44.5-99.3-99.3V480.9H70l446.9-463 446.9 463H698.7z m0 0" fill="#1afa29" p-id="5390"></path></svg>
              <span>周同比 &nbsp;&nbsp;19.96%</span>
              <svg t="1692935225089" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6581" width="16" height="16"><path d="M335 546.6V117.1c0-54.8 44.5-99.3 99.3-99.3h165.4c54.8 0 99.3 44.5 99.3 99.3v429.5h264.7l-446.9 463L70 546.6h265z m0 0" fill="#d81e06" p-id="6582"></path></svg>
            </template>

            <!--响应子组件footer插槽,插入自定义的结构-->
            <template slot="footer">
              <span>日销售额¥ &nbsp;&nbsp;12423</span>
            </template>

          </Detail>
        </el-card>
      </el-col>

      <el-col :span="6">
        <el-card>
          <Detail title="访问量" count=12306>
            <template slot="footer">
              <span>日访问量1234</span>
            </template>
          </Detail>
        </el-card>
      </el-col>

      <el-col :span="6">
        <el-card>
          <Detail title="支付笔数" count=12306>
            <template slot="footer">
              <span>转换率64%</span>
            </template>
          </Detail>
        </el-card>
      </el-col>

      <el-col :span="6">
        <el-card>
          <Detail title="运营活动效果" count=78%>
            <template slot="footer">
              <span>周同比 &nbsp;&nbsp;12%</span>
              <svg t="1692935095365" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5389" width="16" height="16"><path d="M698.7 480.9v429.5c0 54.8-44.5 99.3-99.3 99.3H434c-54.8 0-99.3-44.5-99.3-99.3V480.9H70l446.9-463 446.9 463H698.7z m0 0" fill="#1afa29" p-id="5390"></path></svg>
              <span>日同比 &nbsp;&nbsp;11%</span>
              <svg t="1692935225089" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6581" width="16" height="16"><path d="M335 546.6V117.1c0-54.8 44.5-99.3 99.3-99.3h165.4c54.8 0 99.3 44.5 99.3 99.3v429.5h264.7l-446.9 463L70 546.6h265z m0 0" fill="#d81e06" p-id="6582"></path></svg>
            </template>
          </Detail>
        </el-card>
      </el-col>

    </el-row>
  </div>
</template>

<script>
  import Detail from './Detail'
  export default {
    name:'',
    components:{
      Detail
    }
  }
</script>

### Detail.index.vue
<template>
  <div>
    <div class="card-header">
      <span>{{title}}</span>
      <!--复用组件,使用同一个矢量图-->
      <svg t="1692932780198" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4025" width="16" height="16"><path d="M468.394667 936.448a427.946667 427.946667 0 0 1-42.368-6.485333 431.488 431.488 0 0 1-80.085334-24.832 426.368 426.368 0 0 1-72.533333-39.338667 429.312 429.312 0 0 1-63.146667-52.096 429.269333 429.269333 0 0 1-52.096-63.146667 426.666667 426.666667 0 0 1-39.338666-72.533333 418.602667 418.602667 0 0 1-24.832-80.085333 425.429333 425.429333 0 0 1-6.485334-42.368A434.474667 434.474667 0 0 1 85.333333 512a434.517333 434.517333 0 0 1 2.218667-43.605333 425.514667 425.514667 0 0 1 6.485333-42.368 431.488 431.488 0 0 1 24.832-80.085334 426.666667 426.666667 0 0 1 39.338667-72.533333 429.312 429.312 0 0 1 52.096-63.146667 429.44 429.44 0 0 1 63.146667-52.096 426.325333 426.325333 0 0 1 72.533333-39.338666 418.602667 418.602667 0 0 1 80.085333-24.832 427.349333 427.349333 0 0 1 42.368-6.485334A433.194667 433.194667 0 0 1 512 85.333333a433.493333 433.493333 0 0 1 43.605333 2.218667 427.818667 427.818667 0 0 1 42.368 6.485333 431.488 431.488 0 0 1 80.085334 24.832 426.666667 426.666667 0 0 1 72.533333 39.338667 429.909333 429.909333 0 0 1 63.146667 52.096 429.866667 429.866667 0 0 1 52.096 63.146667 426.666667 426.666667 0 0 1 39.338666 72.533333c5.418667 12.8 10.24 25.984 14.336 39.210667s7.68 27.136 10.538667 40.874666 5.034667 28.16 6.442667 42.368A431.488 431.488 0 0 1 938.666667 512a431.445333 431.445333 0 0 1-2.218667 43.605333 428.458667 428.458667 0 0 1-6.442667 42.368 419.114667 419.114667 0 0 1-24.874666 80.085334 426.666667 426.666667 0 0 1-39.338667 72.533333 429.781333 429.781333 0 0 1-52.096 63.146667 429.866667 429.866667 0 0 1-63.146667 52.096 426.666667 426.666667 0 0 1-72.533333 39.338666 414.293333 414.293333 0 0 1-80.085333 24.832 428.416 428.416 0 0 1-42.368 6.485334A433.493333 433.493333 0 0 1 512 938.666667a433.194667 433.194667 0 0 1-43.605333-2.218667zM145.066667 512a367.36 367.36 0 0 0 366.933333 366.933333 367.36 367.36 0 0 0 366.933333-366.933333A367.36 367.36 0 0 0 512 145.066667 367.36 367.36 0 0 0 145.066667 512z m270.933333 250.666667v-59.733334h66.133333V416H424.533333v-59.733333h117.333334v346.666666h66.133333v59.733334zM482.133333 322.133333v-59.733333h59.733334v59.733333z" p-id="4026"></path></svg>
    </div>
    <div class="card-content">{{count}}</div>
    <!--留坑-->
    <div class="card-charts">
      <slot name="charts">

      </slot>
    </div>
    <div class="card-footer">
      <slot name="footer">

      </slot>
    </div>
  </div>
</template>

<script>
  export default {
    name:'',
    props:['title','count'] // 接收父组件传过来的值
  }
</script>

<style scoped>
  /*自定义的样式*/
  .card-header {
    display: flex;
    justify-content: space-between;
    color: #d9d9d9;
  }
  .card-content {
    font-size: 30px;
    padding: 10px 0px;
  }
  .card-charts {
    height: 40px;
  }
  .card-footer {
    border-top: 1px solid #eee;
    padding: 10px;
  }
</style>