《Vue.js实战》- 留言列表

使用 Render 函数来完成一个留言列表的小功能

练习 1 : 给每条留言都增加 一个删除的功能。
练习 2 :将该示例的 render 写法改写为 template 写法,加以对比,总结出两者的差异性,深刻理解其使用场景。

效果图:

文件:index.html index.js input-render.js input-template.js list-render.js list-template.js  style.css

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>留言列表</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>

    <div id="app" v-cloak style="width: 500px;margin:0 auto;">
        <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" @delete="deleteReply"></list>
    </div>

    <script src="../../vue.min.js"></script>
    <script src="input.js"></script>
    <script src="list.js"></script>
    <script src="index.js"></script>
</body>

</html>

index.js

let app = new Vue({
    el: "#app",
    data() {
        return {
            username: "",
            message: "",
            list: []
        }
    },
    methods: {
        handleSend: function(){
            if(this.username === ""){
                window.alert("请输入昵称");
                return;
            }
            if(this.message === ""){
                window.alert("请输入留言内容");
                return;
            }
            this.list.push({
                name: this.username,
                message: this.message
            });
            this.message = "";
        },
        handleReply: function(index){
            let name = this.list[index].name;
            this.message = "回复@" + name + ":";
            this.$refs.message.focus();
        },
        deleteReply: function(index){
            this.list.splice(index, 1);
        }
    },
})

input-render.js

Vue.component("vInput", {
    props: {
        value: {
            type: [String, Number],
            default: ""
        }
    },
    // render方法
    render: function (h) {
        let _this = this;
        return h("div", [
            h("span", "昵称:"),
            h("input", {
                attrs: {
                    type: "text",
                },
                domProps: {
                    value: this.value
                },
                on: {
                    input: function (event) {
                        _this.value = event.target.value;
                        _this.$emit("input", event.target.value);
                    }
                }
            })
        ])
    }
})

Vue.component("vTextarea", {
    props: {
        value: {
            type: String,
            default: ""
        }
    },
    render: function(h){
        let _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();
        }
    },
})

input-template.js

Vue.component("vInput", {
    template: "<div> \
        <span>昵称:</span> \
        <input type='text' :value='value' @input='inputName'> \
    </div>",
    props: {
        value: {
            type: [String, Number],
            default: ""
        }
    },
    data() {
        return {
            value: this.value
        }
    },
    methods: {
        inputName: function(event){
            this.value = event.target.value;
            this.$emit("input", event.target.value);
        }
    }
})

Vue.component("vTextarea", {
    template: "<div> \
        <span>留言内容:</span> \
        <textarea placeholder='请输入留言内容' :value='value' ref='message' @input='inputMsg'></textarea> \
    </div>",
    props: {
        value: {
            type: String,
            default: ""
        }
    },
    data() {
        return {
            value: this.value
        }
    },
    methods: {
        focus: function () {
            this.$refs.message.focus();
        },
        inputMsg: function(event){
            this.value = event.target.value;
            this.$emit("input", event.target.value);
        }
    }
})

list-render.js

Vue.component("list", {
    props:{
        list: {
            type: Array,
            default: function(){
                return [];
            }
        }
    },
    render: function(h){
        let _this = this;
        let list = [];

        this.list.forEach((msg, index) => {
            let 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);
                            }
                        }
                    }, "回复"),
                    h("a", {
                        attrs: {
                            class: "list-del"
                        },
                        on:{
                            click: function(){
                                _this.deleteReply(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);
        },
        deleteReply: function(index){
            this.$emit("delete", index);
        }
    },
})

list-template.js 

Vue.component("list", {
    template: "<div v-if='list.length'> \
    <div class='list-item' v-for='(item, index) in list'> \
        <span>{{item.name}}:</span> \
        <div class='list-msg'> \
            <p>{{item.message}}</p> \
            <a class='list-reply' @click='handleReply(index)'>回复</a> \
            <a class='list-del' @click='deleteReply(index)'>删除</a> \
        </div>\
    </div>\
    </div> \
    <div v-else class='list-nothing'>留言列表为空</div>",
    props:{
        list: {
            type: Array,
            default: function(){
                return [];
            }
        }
    },
    data() {
        return {
            list: this.list
        }
    },
    methods: {
        handleReply: function(index){
            this.$emit("reply", index);
        },
        deleteReply: function(index){
            this.$emit("delete", index);
        }
    },
})

style.css

[v-cloak]{
    display: none;
}

*{
    padding: 0;
    margin: 0;
}

.message{
    width: 450px;
    text-align: right;
    margin-top: 20px;
}

.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: #3399ff;
    cursor: pointer;
    outline: none;
}

.list{
    margin-top: 50px;
}

.list-item{
    padding: 10px;
    border-bottom: 1px solid #e3e8ee;
    overflow: hidden;
}

.list-item span{
    display: block;
    width: 60px;
    float: left;
    color: #3399ff;
}
.list-msg{
    display: block;
    margin-left: 60px;
    text-align: justify;
}

.list-msg a{
    color: #9ea7b4;
    cursor: pointer;
    float: right;
}

.list-msg a:hover{
    color: #3399ff;
}

.list-nothing{
    text-align: center;
    color: #9ea7b4;
    padding: 20px;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值