先贴效果图
先封装一个js
import * as echarts from "echarts";
export const zhexiantuChart = (id, data) => {
const { xData, yData, cart } = data;
const color = ["#0FF9A9", "#1F82FF", "#E2AE00"];
let series = [];
let legend = [];
yData.map((item, index) => {
legend.push(item.name);
console.log(item);
series.push(
{
...item,
type: "line",
smooth: true,
},
// 闪烁点的重点是以下配置
{
// 设置涟漪特效动画
type: "effectScatter",
// 有三种: cartesian2d(二维的直角坐标系) polar(极坐标系) geo(地理坐标系) ,此需求使用cartesian2d
coordinateSystem: "cartesian2d",
// 单个闪烁点 ↓
// data: [{value:[xData[4],item.data[4]],symbolSize:8}], //2d坐标系--[x轴, y轴, 标记大小]
data: cart, //2d坐标系--[x轴, y轴, 标记大小]
// 多个闪烁点 ↓
// 方法一 -- start:
// data: [{value:['Mon',820],symbolSize:10},{value:['Tue',932],symbolSize:10}],
// 方法一 -- end
// 方法二 -- start:
// data: [['Mon',820],['Tue',932]], //2d坐标系--[x轴, y轴, 标记大小]
// symbolSize: 10,
// 方法二 -- end
// 何时显示特效:'render'-绘制完成后显示特效 'emphasis'-高亮(hover)的时候显示特效
showEffectOn: "render",
// 涟漪特效配置
rippleEffect: {
// 波纹的绘制方式,可选'stroke'和'fill'
brushType: "stroke",
},
hoverAnimation: true,
itemStyle: {
normal: {
color: "#1F82FF",
shadowBlur: 30,
shadowColor: "#fff",
},
},
zlevel: 1,
}
// type: "line",
// stack: "Total",
// lineStyle: {
// normal: {
// width: 2,
// },
// },
// smooth: true,
// symbolSize: 4,
// color: color[index],
// ...item,
);
});
let chart = echarts.init(document.getElementById(id));
chart.clear(); //画图之前,清除内容
chart.setOption({
legend: {
x: "center",
y: "bottom",
itemWidth: 21,
itemHeight: 7,
textStyle: {
fontSize: 10,
color: "#21E4FE",
},
data: legend,
selectedMode: true, //取消图例上的点击事件
},
grid: {
top: "12%",
left: "2%",
right: "3%",
bottom: "18%",
containLabel: true,
},
tooltip: {
trigger: "axis",
backgroundColor: "rgba(0,72,176,.9)",
borderColor: "#1ED1EB",
formatter: (res) => {
let str = "";
res.map((item) => {
str += `<p style="font-size: 12px;line-height: 22px;color: #fff;">${item.seriesName}<span style="padding-left: 10px;">${item.value}</span></p>`;
});
const htmlStr = `<div class="tooltip">
<p style="font-size: 14px;line-height: 20px;color: #fff;">${res[0].name}</p>
<div style="padding-top: 5px;">${str}</div>
</div>`;
return htmlStr;
},
},
xAxis: {
type: "category",
boundaryGap: true, // 坐标轴两边是否留白
axisLabel: {
interval: 0, //可以设置成 0 强制显示所有标签。如果设置为 1,表示『隔一个标签显示一个标签』,如果值为 2,表示隔两个标签显示一个标签,以此类推。
textStyle: {
color: "#21E4FE",
fontSize: 10,
},
},
axisLine: {
show: true,
lineStyle: {
color: "#1C52A2",
width: 1,
},
},
axisTick: {
show: false, //不显示刻度
},
data: xData,
},
yAxis: {
type: "value",
axisLabel: {
interval: 0,
textStyle: {
color: "#21E4FE",
fontSize: 10,
},
},
splitLine: {
show: true,
lineStyle: {
type: "dashed",
color: "#1C52A2",
width: 1,
},
},
},
series,
});
};
在页面中
<div id="zhexiantu" class="chart"></div>
<button @click="getto">变化列表</button>
<button @click="getlist(list[0])">选中第一个月份</button>
<button @click="getlist(list[1])">选中第二个月份</button>
<button @click="getlist(list[2])">选中第三个月份</button>
<button @click="getlist(list[3])">选中第四个月份</button>
<button @click="getlist(list[4])">选中第五个月份</button>
script
<script>
import * as echarts from "echarts";
import { zhexiantuChart } from "@/utils/zhexiantu";
export default {
data() {
return {
list: [
{
time: "2022-06",
num: "133",
},
{
time: "2022-07",
num: "225",
},
{
time: "2022-08",
num: "369",
},
{
time: "2022-09",
num: "53",
},
{
time: "2022-10",
num: "97",
},
],
title: [],
nums: [],
ble: "",
btl: "",
};
},
mounted() {
this.list.map((item, index) => {
this.title.push(item.time);
this.nums.push(item.num);
});
zhexiantuChart("zhexiantu", {
xData: this.title,
yData: [
{
data: this.nums,
},
],
cart: [{ value: [this.list[4].time, this.list[4].num], symbolSize: 8 }],
});
},
methods: {
getlist(data) {
console.log(data);
zhexiantuChart("zhexiantu", {
xData: this.title,
yData: [
{
data: this.nums,
},
],
cart: [{ value: [data.time, data.num], symbolSize: 8 }],
});
},
getto() {
this.list = [];
this.title = [];
this.nums = [];
this.list = [
{
time: "2022-07",
num: "133",
},
{
time: "2022-08",
num: "225",
},
{
time: "2022-09",
num: "3691",
},
{
time: "2022-10",
num: "531",
},
{
time: "2022-11",
num: "971",
},
];
},
gettos() {
this.list = [
{
time: "2022-07",
num: "133",
},
{
time: "2022-08",
num: "225",
},
{
time: "2022-09",
num: "3691",
},
{
time: "2022-10",
num: "531",
},
{
time: "2022-11",
num: "971",
},
];
},
},
watch: {
list: {
handler(val) {
console.log(val);
this.list.map((item, index) => {
this.title.push(item.time);
this.nums.push(item.num);
});
console.log(zhexiantuChart);
zhexiantuChart("zhexiantu", {
xData: this.title,
yData: [
{
data: this.nums,
},
],
cart: [
{ value: [this.list[4].time, this.list[4].num], symbolSize: 8 },
],
});
},
},
},
};
</script>
样式 随便写的
<style scoped>
.index {
height: 100vh;
}
#zhexiantu {
width: 96vw;
height: 30vh;
border: 1px solid red;
}
</style>
vue3 小来一段
1、setup函数
总结:Vue3.0中一个新的配置向,值为一个函数,组件中所有用到的:数据、方法等等,均要配置在setup中。
setup函数的两种返回值:
若返回一个对象,则对象中的数据、方法、在模板中均可直接使用(重点)
<script setup>
var name = "marry";
var obj = {
age: 18,
gender: "女",
class: '二'
}
</script><template>
<div>
<span>{{obj.class}}班的{{name}}是一名{{obj.gender}}生,今年{{obj.age}}岁了~~~</span>
</div>
</template>
//二班的marry是一名女生,今年18岁了~~~
若返回一个渲染函数,则可以自定义渲染内容(了解)
//页面中会显示一个h1标签,标签的内容是"vue3返回渲染函数"
<script>
import {h} from 'vue'
export default {
setup() {
// 返回一个渲染函数
// h相当于document.CreateElement()
return ()=>{return h("h1","vue3返回渲染函数")}
}
}
</script>
注意:
虽然它可以使用Vue2.0的配置,但是不要2.0 \3.0一起混用;
Vue2.x配置(data,methods,computed…)中可以访问setup中的属性,方法,但在setup中不能访问到Vue2.x配置(data,methods,computed…)
如有重名,setup优先
setup不能是一个async函数,因为返回值不再是return的对象,而是Promise,模板看不到return对象中的属性
setup在组件加载期间,只会运行一次。
语法糖:在script里面加入 setup , 这个属性会让打包工具打包时,直接帮我们把setup函数内部声明的变量、函数return 然后组件就可以直接使用
setup函数是处于 生命周期函数 beforeCreate 和 Created 两个钩子函数之前的函数
执行 setup 时,组件实例尚未被创建(在 setup() 内部,this 不会是该活跃实例的引用,即不指向vue实例,Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了 undefined)
setup 函数中的 props 是响应式的,当传入新的 prop 时,它将被更新。但是,因为 props 是响应式的,你不能使用 ES6 解构,因为它会消除 prop 的响应性。
从 setup() 中返回的对象上的 property 返回并可以在模板中被访问时,它将自动展开为内部值。不需要在模板中追加 .value
2、ref函数
总结:定义一个响应式的数据
import {ref} from “vue”
语法:const xxx = ref(“value”)
创建一个包含响应式的数据的引用对象(reference对象)
js中操作数据:xxx.value
模板中读取数据不需要.value,直接
{{xxx}}
注意
接收的数据类型可以是基本数据类型也可以是引用数据类型(对象,数组等 xxx.value.属性值/[下标])
基本类型的数据:响应式依然是靠Object.defineProperty()的get和set完成的
对象类型的数据:内部“求助”了Vue3.0的一个新的函数------reactive函数
<script setup>
import {
ref
} from "vue"
var name = "marry";
var obj = ref({
age: 18,
gender: "女",
class: '二'
})function change() {
obj.value.age++
}
</script>
<template>
<div>
<span>{{obj.class}}班的{{name}}是一名{{obj.gender}}生,今年{{obj.age}}岁了~~~</span>
<button @click="change">年龄+1</button>
</div>
</template>
3、reactive函数
作用:定义一个对象类型的响应式数据(基本数据类型别用它,用ref函数)
引入:import {reactive} from ‘vue’
语法:const 代理一个对象 = reactive(被代理的对象) 接收一个对象(或数组),返回一个代理器对象(proxy对象)
reactive定义的响应式数据是“深层次的”
内部基于ES6的Proxy实现,通过代理对象内部的数据都是响应式的
<script setup>
import {
reactive
} from "vue"
var name = "marry";
var obj = reactive({
age: 18,
gender: "女",
class: '二'
})function change() {
obj.age++
}
</script>
<template>
<div>
<span>{{obj.class}}班的{{name}}是一名{{obj.gender}}生,今年{{obj.age}}岁了~~~</span>
<button @click="change">年龄+1</button>
</div>
</template>
ref \reactive 区别用法?
都是用来放响应式数据;
引入方式: ref: import {ref} from ‘vue’ / import {reactive} from ‘vue’
ref( )里面放的是基本数据,和嵌套层数不是很深的引用数据; / reactive( )基本数据不用他,里面放嵌套层数比较深的引用数据;
ref 用里面的数据时,数据方法**.value**里面, / reactive 用里面的数据时 ,直接使用。
响应式设计原理:ref: 监听了value的改变,劫持value属性的setter ,getter ,因此ref一般用在基本数据,或者嵌套不深的引用数据上; / reactive: 和ref一样,但是底层采用的是ES6的Proxy代理了整个引用数据。
4、Vue3.0中的响应式原理
vue2.0的响应式
实现原理
对象类型:通过Object.definedProperty()对属性的读取、修改进行拦截(数据劫持)
数组类型:通过重写更新数据的一系列方法来实现拦截。(对数组的方法进行了包裹)
Object.defineProperty(data,"count",{
get(){},
set(){}
})
存在问题:
新增属性,删除属性都不会刷新界面
直接通过下标修改数组,界面不会自动更新
let person = {
name:"李国栋",
age:18
}
let p = {};
Object.defineProperty(p,"name",{
get(){
console.log("有人读取数据时调用");
return person.name
},
set(value){
console.log("有人修改了数据,我要去更新页面");
person.name = value
}
})
vue3.0的响应式
实现原理
通过Proxy(代理):拦截对象中任意属性的变化,包括:属性的读写,属性的添加,属性的删除等
通过Reflect(反射):对被代理对象的属性进行操作
MDN文档中描述的Proxy与Reflect:
Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
Reflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
let person = {
name:"李国栋",
age:18
}
let p = new Proxy(person,{
// 读取
get(target,proname){
// target表示原对象 proname表示对象名
console.log("有人读取了person上的属性",target);
return target[proname]
},
// 修改或者增加
set(target,proname,value){
console.log("有人修改了person上的属性,我要去更新了");
target[proname] = value
},
// 删除
deleteProperty(target,proname){
console.log("有人删除了person上面的属性,我要去调用了");
return delete target[proname]
},
});
## 5、组件
引入:import xxx from (“组件路径”)
引入后直接使用:
## 6、计算属性
引入:import {computed} from “vue”
使用:computed( 函数)
<script setup>
import {
ref,
reactive,
computed
} from "vue"let arr = reactive([{
title: '鱼香肉丝',
price: 20,
count: 1
},
{
title: '水煮肉片',
price: 35,
count: 1
},
{
title: '白米饭',
price: 3,
count: 1
},
])
let total = computed(() => {
console.log(66666, "计算总价")
return arr.reduce((n1, n2) => {
return n1 + n2.price * n2.count
}, 0)
})
let change1 = () => {
arr[0].count = 10
}
function add(index) {
arr[index].count++
}
function des(index) {
arr[index].count--
}
</script>
<template>
<div class="box"> <div v-for="(el,index) in arr">
<div>{{el.title}}----{{el.price}}元----
<button @click="des(index)">-</button>
<span>{{el.count}}</span>
<button @click="add(index)">+</button>
</div>
</div>
<button @click="change1">修改</button>
<button>{{total}}元</button>
</div>
</template>