美文网首页我爱编程
vue2.0入手踩的第五个坑-prop

vue2.0入手踩的第五个坑-prop

作者: 麦壳儿UIandFE2 | 来源:发表于2018-06-21 20:58 被阅读2597次

    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数据流是单向传递的,所以报警告。

    相关文章

      网友评论

        本文标题:vue2.0入手踩的第五个坑-prop

        本文链接:https://www.haomeiwen.com/subject/pwvcyftx.html