需求:


  • 需要在文章 、视频列表、帖子、直播、专题等评论区发布 评论。
  • 评论发布框为一个弹出层。
  • 使用vant实现。
    我感觉多处用到了这个弹出层,准备封装成一个子组件以便调用。

上图
弹出层位置
弹出层样子


这里遇到了个问题,就是不知道如何为子组件内部的孙组件的v-model传值。
这里数据我一直想不通的地方在于双向绑定需要事件,我想不到van-popup的事件是什么,后来才知道原来vue官方就说明了默认的v-model事件是input,默认绑定的值是value
查阅了好多地方,找到了两种解决方法,最终是在vant官方微信2群解决的,在此感谢 @A Lemon 提供的第一种方法和 @陪我笑闹人间 提供的第二种方法


首先是使用第一种方法实现思路
  1. 父组件内调用子组件使用v-model
  2. 子组件内的孙组件(van-popup)的v-model拆分成:value和@input
  3. 然后通过$emit完成数据同步

细节:

  • van-popup绑定的value对应从父组件内传来的props内的value
  • van-popup的input事件生成的新值弹射到父组件v-model对应的默认input事件参数

官方文档如是说

具体实现代码

先贴简单的父组件内调用子组件的代码

 <comment-popup v-model="showPostDialog" />

然后是子组件的代码

<template>
    <van-popup
        class="comment-popup"
        position="bottom"
        overlay-class="opacity"
        :value="value"
        @input="val => this.$emit('input', val)"
    >
    <!-- 内部构造多余,请忽略,弹出层内部slot自己随便写 -->
        <div class="publish-comment van-hairline--top">
            <van-uploader
                ref="up"
                v-show="upimage"
                v-model="fileList"
                :max-count="1"
                :after-read="afterRead"
                @delete="delImage"
            />
            <div class="field">
                <van-field
                    v-model="comment_content"
                    rows="3"
                    autosize
                    type="textarea"
                    maxlength="50"
                    placeholder="优质评论会被优先展示"
                    :border="false"
                />
                <van-button
                    :disabled="disablePublish"
                    @click="comment"
                    color="hotpink"
                    size="small"
                    >发布</van-button
                >
            </div>
            <div class="fnbar">
                <i class="icon image" @click="upImage"></i>
            </div>
        </div>
    </van-popup>
</template>    
<script> 
import { Button, Uploader, Popup, Field } from "vant";
Vue.use(Field)
    .use(Uploader)
    .use(Popup)
    .use(Button);
export default {
    name: "comment-popup",
    // props: ["value" ],
    props: {
        value: {
            type: Boolean,
            default: false
        },
        
    },
    data: function() {
        return {
           
        };
    }
}
//多余的无用代码就不贴了(虽然也贴了一些了)
//......
 </script>



第二种方法使用sync语法(vue2.3+)用到了computed的getter和setter

先贴官方文档,贴了看不懂,最后还是要看实现代码比较清楚。
sync的官方说明

具体实现代码

先贴父组件内调用子组件的代码

  <comment-popup  :popup.sync="showPostDialog"  />

然后是子组件的代码

<template>
    <van-popup
        class="comment-popup"
        position="bottom"
        overlay-class="opacity"
        v-model="vanpopup"
    >
    </van-popup>
</template>

<script>
import { Popup } from "vant";
Vue.use(Popup);
export default {
    name: "comment-popup",
    props: {
        popup: {
            type: Boolean,
            default: false
        }
    },
    computed: {
        vanpopup: {
            get() {
                return this.popup;
            },
            set(value) {
                this.$emit("update:popup", value);
            }
        }
    }
};
</script>

看懂的人自然就懂,不然我这解释其实也很无力。
首先是父组件通过sync关键字设置了语法糖。
然后是把子组件内的孙组件van-popup的v-model双向绑定通过computed给他拆分成get和set。然后在set内调用$emit发射数据。
我一直两种方法都无法成功的原因是

  1. 找不到popup的事件名。
  2. 不清楚时间绑定的单向是否用到了vue的 $data 。

这里的两种方法都是直接把属性绑定到props上,不过更新数据都还是通过$emit发射的。关键点不在操作,而是认知,认知如何绑定到正确的属性,如何正确的发射事件,如何拆分。

Logo

前往低代码交流专区

更多推荐