Render函数:留言列表组件

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="Vue.2.6.10.js"></script>
</head>
<style>
    [v-cloak]{
        display: none;
    }
    *{
        padding: 0;
        margin: 0;
    }
    .message{
        width: 450px;
        text-align: right;
    }
    .message div{
        margin-bottom: 12px;
    }
    .message span{
        display: inline-block;
        width: 100px;
        vertical-align: top;
    }
    .message input, .message textarea{
        width: 300px;
        height: 32px;
        padding: 0 6px;
        color:#657180;
        border: 1px solid #d7dde4;
        border-radius: 4px;
        cursor: text;
        outline: none;
    }
    .message input:focus, .message textarea:focus{
        border: 1px solid #3399ff;
    }
    .message textarea{
        height: 60px;
        padding: 4px 6px;
    }
    .message button{
        display: inline-block;
        padding: 6px 15px;
        border: 1px solid #39f;
        border-radius: 4px;
        color:#fff;
        background-color: #39f;
        cursor: pointer;
        outline: none;
    }
    .list{
        margin-top: 50px;
    }
    .list-item{
        padding: 10px;
        border-bottom: 1px solid #e3e833;
        overflow: hidden;
    }
    .list-item span{
        display: block;
        width: 60px;
        float: left;
        color:#39f;
    }
    .list-msg{
        display: block;
        width: 60px;
        text-align: justify;
    }
    .list-msg a{
        color: #9ea7b4;
        cursor: pointer;
        float: right;

    }
    .list-msg a:hover{
        color:#39f;
    }
    .list-nothing{
        text-align: center;
        color:#9ea7b4;
        padding: 20px;

    }

</style>
<body>
    <div id="app" v-cloak style="width: 500px;margin:0 auto; margin-top: 30px;">
        <div class="message">
            <v-input v-model='username'></v-input>
            <v-textarea v-model='message' ref="message"></v-textarea>
            <button @click='handleSend'>发布</button>
        </div>
        <list :list='list' @reply='handleReply'></list>
    </div>
</body>
<script>
    Vue.component('vInput',{
        props:{
            value:{
                type:[String,Number],
                default:''
            }
        },
        render(h) {
            var _this = this;
            return h('div',[
                h('span','昵称:'),
                h('input',{
                    attrs:{
                        type:'text'
                    },
                    domProps:{
                        value:this.value  
                    },
                    on:{
                        //v-model在render中需要自己实现嗷
                        input:function(event){
                            _this.value = event.target.value;
                            _this.$emit('input',event.target.value)
                        }
                    }
                })
            ])
        },
    });

    Vue.component('vTextarea',{
        props:{
            value:{
                type:String,
                default:''
            }
        },
        render(h) {
            var _this = this;
            return h('div',[
                h('span','留言内容'),
                h('textarea',{
                    attrs:{
                        placeholder:'说点什么'
                    },
                    domProps:{
                        value:this.value
                    },
                    ref:'message',
                    on:{
                        input:function(event){
                            _this.value = event.target.value;
                            _this.$emit('input',event.target.value)
                        }
                    }
                })
            ])
        },
        methods:{
            focus:function(){
                this.$refs.message.focus()
            }
        }
    })

    Vue.component('list',{
        props:{
            list:{
                type:Array,
                default:function(){
                    return [];
                }
            }
        },
        render(h) {
            var _this = this;
            var list = [];
            this.list.forEach(function(msg,index){
                var node = h('div',{
                    attrs:{
                        class:'list-item'
                    }
                },[
                    h('span',msg.name + ":"),
                    h('div',{
                        attrs:{
                            class:'list-msg'
                        }
                    },[
                        h('p',msg.message),
                        h('a',{
                            attrs:{
                                class:'list-reply'
                            },
                            on:{
                                click:function(){
                                    _this.handleReply(index);
                                }
                            }
                        },'回复')
                    ])
                ])
                list.push(node);
            });
            if(this.list.length){
                return h('div',{
                    attrs:{
                        class:'list'
                    },
                },list);
            }else{
                return h('div',{
                    attrs:{
                        class:'list-nothing'
                    },
                },'留言列表为空嗷,说点什么吧~')
            }
        },
        methods:{
            handleReply:function(index){
                this.$emit('reply',index);
            }
        }
    });

    //发布留言需要的数据主要有:昵称、留言内容,发布操作在根实例内完成,留言列表数据同样获取自app
    var app = new Vue({
        el:"#app",
        data:{
            username:'',
            message:'',
            list:[]
        },
        methods: {
            handleSend:function(){
                if(this.username === ''){
                    window.alert('要输入昵称噢');
                    return
                }
                if(this.message === ''){
                    window.alert('说点什么吧~');
                    return
                }
                this.list.push({
                    //List是一个对象数组?
                    name:this.username,
                    message:this.message
                });
                console.log(this.list);
                this.message = '';//置空输入栏
            },
            handleReply:function(index){
                var name = this.list[index].name;
                this.message = '回复@' + name + ":";
                this.$refs.message.focus();
            }
        },
    });

    //分析一哈:
    //v-input组件:生成<span>昵称</span>与输入栏,
    // 并设置输入栏的值为这个组件得到的值:在render函数中用on选项实现v-model
    //(需要domPropsyuon配合来实现双向绑定)当触发input事件,将v-input组件的value更新为
    //同时向根实例发送一个input事件

    //v-textarea组件:生成<span>留言内容<span>与文本输入域,在这里同样手动实现v-model
    //该组件中多包含了一个focus方法,this.$refs.message.focus()使得这个实例中render函数生成的textarea获得焦点

    //点击回复按钮,调用handleSend(),将昵称与留言内容传入list,置空输入栏,

    //▲list组件
    //接收到list后,使用list来渲染留言列表,同时在‘回复’按钮上传入昵称对应的index,当点击时调用handleReply方法
    //它的reply方法是为了调用根实例的同名方法
    //
</script>
</html>
View Code

预览效果:

这几个Vue的小组件写下来,写的我真的好佩服尤大...

posted @ 2019-06-30 16:26  林不渡  阅读(286)  评论(0编辑  收藏  举报