1:浏览器报错
vue.js:584 [Vue warn]: 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: "imgSrc"
image.png
2:源码
错误的:
子组件:
html:
<img :src="imgSrc" style="width: 90%;">
prop:
props: {
imgSrc: {
type: String,
required: true
}
methods:
/**
* @desc:显示弹窗
* @param:parentToChildData [string] 父组件向子组件传递的数据,这里是图片地址
* @param:isVisible [boolean] 弹窗是否可见
* */
isShowDia(parentToChildData, isVisible){
let self = this
if (!parentToChildData) {
return
}
self.dialogIsVisible = isVisible
// self.imgSrc - prop 中传递的量
self.imgSrc = parentToChildData //<---问题出现在这里,这里操作了this身上的prop上的imgSrc
},
此时对应的父组件:
html:
<zoomInViewImage ref="zoomInViewImageDom" ></zoomInViewImage>
js:
import zoomInViewImage from '@/components/common/banner/zoomInViewImage'
components: {zoomInViewImage},
data() {
return {
imgSrc: ""
};
methods:{
openZoomImageFn(imgSrc){
let self = this
self.$refs['zoomInViewImageDom'].isShowDia(imgSrc, true)
}
}
问题出现在子组件中 方法中最后一句代码,这里对prop 中定义的imgSrc变量进行了赋值操作,其值本应来自父组件传递,不倡导你在子组件中对其做更改,也就是单向数据流。摘录一段官方的说法。
单向数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
其实父组件这么写,可以不需要prop进行值的传递,因为在父组件中是可以调到子组件的方法的,那么把这个子组件的isShowDia方法再封一层就可以把当前组件的参数传递进去了。所有有两种修正思路。
修正后:思路1-prop
子组件:
html:
<img :src="imgSrc" style="width: 90%;">
js:
props: {
imgSrc: {
type: String,
required: true
}
},
isShowDia(parentToChildData, isVisible){
let self = this
if (!parentToChildData) {
return
}
self.dialogIsVisible = isVisible
// self.imgSrc - prop 中传递的量
self.imgSrc = parentToChildData
},
父组件:
这里注意:因为js中的prop采用了驼峰写法imgSrc ,写到标签身上变成属性时候要转 短横线形式 img-src。camelCase => came-case
html:
<zoomInViewImage ref="zoomInViewImageDom" :img-src="imgSrc"></zoomInViewImage>
js:
import zoomInViewImage from '@/components/common/banner/zoomInViewImage'
components: {zoomInViewImage},
data() {
return {
imgSrc:""
}
},
openZoomImageFn(imgSrc){
let self = this
self.$refs['zoomInViewImageDom'].isShowDia(imgSrc, true)
self.imgSrc = imgSrc //<---在这里完成赋值,然后通过标签身上的prop属性把值传递给子组件
},
修正后:思路2-利用父中调子中的函数传参
子组件:
html:
<img :src="imgSrc" style="width: 90%;">
js:
data() {
return {
imgSrc:""
}
},
/**
* @desc:显示弹窗
* @param:parentToChildData [string] 父组件向子组件传递的数据,这里是图片地址
* @param:isVisible [boolean] 弹窗是否可见
* */
isShowDia(parentToChildData, isVisible){
let self = this
if (!parentToChildData) {
return
}
self.dialogIsVisible = isVisible
// self.imgSrc - prop 中传递的量
self.imgSrc = parentToChildData
},
父组件:
html:
<!--图片放大-->
<zoomInViewImage ref="zoomInViewImageDom" ></zoomInViewImage>
js:
import zoomInViewImage from '@/components/common/banner/zoomInViewImage'
components: {zoomInViewImage},
openZoomImageFn(imgSrc){
let self = this
self.$refs['zoomInViewImageDom'].isShowDia(imgSrc, true)
},
完整代码:
子组件
<template>
<el-dialog id="imgDia" title="" :visible.sync="dialogIsVisible">
<img :src="imgSrc" style="width: 90%;">
</el-dialog>
</template>
<script>
export default {
// 组件的名称
name: 'zoomInViewImage',
// props 可以是数组或对象,用于接收来自父组件的数据
props: {
imgSrc: {
type: String,
required: true
}
},
// 数据绑定
data() {
return {
dialogIsVisible: false,
}
},
methods: {
/**
* @desc:显示弹窗
* @param:parentToChildData [string] 父组件向子组件传递的数据,这里是图片地址
* @param:isVisible [boolean] 弹窗是否可见
* */
isShowDia(parentToChildData, isVisible){
let self = this
if (!parentToChildData) {
return
}
self.dialogIsVisible = isVisible
},
// 关闭弹窗
}
}
</script>
<style lang="less" rel="stylesheet/less">
#imgDia {
.el-dialog {
background: none !important;
box-shadow: none;
}
.el-dialog__headerbtn .el-dialog__close {
color: #fff;
}
}
</style>
父组件
<!--/*
* @Author: linchaoliang
* @Date: 2018-6-19 09:57:39
* @Last Modified by: Macrolam
* @Last Modified time: 2018-6-20 09:57:35
*/-->
<!-- 查询列表模板 -->
<template>
<el-container id="bannerMan" class="search__list_for_table">
<el-main>
<el-row class="select_conditions mgt10">
<!-- 需要展示的结果页面 不可以删除 没有结果 做什么搜索 -->
<el-row class=" result__tabel">
<!-- 表格展示区 如果是其他的内容不是表格就把下面换了吧 -->
<el-table
:data="listData"
v-loading='loading'
style="width: 100%"
ref="multipleTable"
:empty-text="$t('message.label.no_data')"
max-height="700"
>
<!--缩略图-->
<el-table-column
:label="$t('message.banMan_list.thumbnail')"
width="150">
<template slot-scope="scope">
<a :href="scope.row.imgSrc" target="_blank">
<img :src="scope.row.imgSrc" style="width: 90px;height:60px;">
</a>
<i class="el-icon-zoom-in" @click="openZoomImageFn(scope.row.imgSrc_2)"
style="position: relative;top: -20px;left: 8px;cursor:pointer;"></i>
</template>
</el-table-column>
</el-table>
</el-row>
</el-row>
</el-main>
<!--图片放大-->
<zoomInViewImage ref="zoomInViewImageDom" :img-src="imgSrc"></zoomInViewImage>
</el-container>
</template>
<script>
// 混合查询的方法
import {listSearchMixin} from "@/script/mixin/mixin"
import banManData from "../../../../test/mockData/banMan"
/*todo*/
import {api} from "@/api/api"
import zoomInViewImage from '@/components/common/banner/zoomInViewImage'
export default {
// 组件名称
name: "bannerMan",
// 混合模式, 复用组件的内容
mixins: [listSearchMixin],
// 父子通信
props: {},
computed: {},
// 数据绑定
data() {
return {
labelPosition: 'left',
optionArr: banManData.statusArr,
listData: banManData.list, /*todo*/
imgSrc: ""
};
},
// 组件
components: {zoomInViewImage},
// 方法 查询方法默认为 search方法 无需再次定义 直接使用即可
methods: {
// 重置查询条件 在这里重置查询条件吧
reset(){
this.params = {}
// 页码
this.page = 1
// 一页显示多少条数据
this.page_size = 20
},
openZoomImageFn(imgSrc){
let self = this
self.$refs['zoomInViewImageDom'].isShowDia(imgSrc, true)
self.imgSrc = imgSrc
},
},
};
</script>
<style lang="less" rel="stylesheet/less">
</style>
3:原因:
把两种方式混到一起,prop数据流是单向传递的,所以报警告。
网友评论