今天工作遇到一个问题,vue中,父组件调用了子组件,初始化的时候可以正确显示。需要实时监控后台数据,向子组件传递,更新页面。
百度了一下,说使用watch可以监听。
试了一下,发现并不能改变。debug模式看了一下,数据已经接收到了,因为子组件还有孙子组件。这部分没有进行监听,修改了孙子组件,发现可以在页面上看到效果了。
这时候,日志中会报错
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "startVal"
发现是因为子组件中如果直接更新操作prop值,有风险,可能会影响到父组件,所以在子组件中建变量来接收存储prop值的动态更新,不直接去修改prop值,问题解决
父组件
<style lang="less">
@import "./";
@import "../../styles/";
</style>
<template>
<div>
<div v-show="currNav=='xboot'">
<h1>欢迎来到后台管理</h1>
</div>
<!-- <div v-show="currNav=='xboot-show'"><show/>
</div> -->
<div v-show="currNav=='onemap'">
<Row :gutter="10">
<Col :md="24">
<Row :gutter="5">
<Col :xs="24" :sm="12" :md="6" :style="{marginBottom: '10px'}">
<infor-card id-name="user_created_count" :end-val="" iconType="ios-hammer" color="#2d8cf0" intro-text="当前服务器总量"></infor-card>
</Col>
<Col :xs="24" :sm="12" :md="6" :style="{marginBottom: '10px'}">
<infor-card id-name="visit_count" :end-val="" iconType="ios-contact" color="#64d572" :iconSize="50" intro-text="数据库总量"></infor-card>
</Col>
<Col :xs="24" :sm="12" :md="6" :style="{marginBottom: '10px'}">
<infor-card id-name="collection_count" :end-val="" iconType="md-navigate" color="#ffd572" intro-text="导出操作执行中总量"></infor-card>
</Col>
<Col :xs="24" :sm="12" :md="6" :style="{marginBottom: '10px'}">
<infor-card id-name="transfer_count" :end-val="" iconType="md-podium" color="#f25e43" intro-text="导出操作成功总量"></infor-card>
</Col>
</Row>
</Col>
</Row>
<Row :gutter="10">
<Card>
<p slot="title" class="card-title">
<Icon type="md-map"></Icon>
执行状态
</p>
<div class="data-source-row">
<visite-volume></visite-volume>
</div>
</Card>
</Row>
</div>
</div>
</template>
<script>
import cityData from "./map-data/";
import homeMap from "./components/";
import visiteVolume from "./components/";
import userFlow from "./components/";
import countUp from "./components/";
import inforCard from "./components/";
import Cookies from "js-cookie";
import { getTotal } from "@/api/index";
export default {
name: "home",
components: {
homeMap,
visiteVolume,
userFlow,
countUp,
inforCard
},
data() {
return {
showVideo: false,
count: {
createUser: 0,
visit: 0,
collection: 0,
transfer: 0
},
cityData: cityData,
newToDoItemValue: "",
city: "",
weather: "",
username: ""
};
},
computed: {
currNav() {
return this.$;
},
avatarPath() {
return ;
}
},
methods: {
getTotal() {
let that = this;
getTotal("").then(res => {
if ( == true) {
= ;
= ;
= ;
= ;
}
});
},
timer() {
return setInterval(()=>{
();
},5000)
}
},
mounted() {
();
();
},
destroyed(){
clearInterval();
}
};
</script>
子组件
<style lang="less">
@import './styles/';
</style>
<template>
<Card :padding="0">
<div class="infor-card-con">
<Col class="infor-card-icon-con" :style="{backgroundColor: color, color: 'white'}" span="8">
<Row class="height-100" type="flex" align="middle" justify="center">
<Icon :type="iconType" :size="iconSize"></Icon>
</Row>
</Col>
<Col span="16" class="height-100">
<Row type="flex" align="middle" justify="center" class="height-100">
<count-up
class="infor-card-count user-created-count"
:id-name="idName"
:end-val="endValue2"
:start-val="startValue2"
:color="color"
:countSize="countSize"
:countWeight="countWeight"
>
<p class="infor-intro-text" slot="intro">{{ introText }}</p>
</count-up>
</Row>
</Col>
</div>
</Card>
</template>
<script>
import countUp from './';
export default {
name: 'inforCard',
components: {
countUp
},
watch: {
endVal(newValue, oldValue) {
//注意这里接收,不能直接更新prop值,需要定义变量,否则会提示有风险更新父组件
this.endValue2 = newValue
this.startValue2 = oldValue
//('子组件inforcard接收到new:'+newValue+" old:"+oldValue);
},
},
data() {
return {
endValue2:0,
startValue2:0
};
},
props: {
idName: String,
endVal: Number,
startVal:{
type: Number,
default: 0
},
color: String,
iconType: String,
introText: String,
countSize: {
type: String,
default: '30px'
},
countWeight: {
type: Number,
default: 700
},
iconSize: {
type: Number,
default: 40
}
}
};
</script>
子组件的子组件
<template>
<div>
<p :class="className" :style="{textAlign: 'center', color: color, fontSize: countSize, fontWeight: countWeight}"><span v-cloak :>{{ startVal }}</span><span>{{ unit }}</span></p>
<slot name="intro"></slot>
</div>
</template>
<script>
import CountUp from 'countup';
function transformValue (val) {
let endVal = val;
let unit = '';
return {
val: endVal,
unit: unit
};
}
export default {
data () {
return {
unit: '',
demo: {}
};
},
name: 'countUp',
props: {
idName: String,
className: String,
startVal: {
type: Number,
default: 0
},
endVal: {
type: Number,
required: true
},
decimals: {
type: Number,
default: 0
},
duration: {
type: Number,
default: 2
},
delay: {
type: Number,
default: 500
},
options: {
type: Object,
default: () => {
return {
useEasing: true,
useGrouping: true,
separator: ',',
decimal: '.'
};
}
},
color: String,
countSize: {
type: String,
default: '30px'
},
countWeight: {
type: Number,
default: 700
},
introText: [String, Number]
},
mounted () {
this.$nextTick(() => {
setTimeout(() => {
let res = transformValue();
let endVal = ;
= ;
let demo = {};
= demo = new CountUp(, , endVal, , , );
if (!) {
();
}
}, );
});
},
watch: {
endVal (val) {
let res = transformValue(val);
let endVal = ;
= ;
let demo = {};
= demo = new CountUp(, , endVal, , , );
if (!) {
();
}
// (endVal);
}
}
};
</script>