Vue.js(一到五总结)-小Demo-留言表

如果看完了Vue.js入门1-5,就可以很容易的理解这个小Demo,这个Demo我们来模拟一个留言表。

1.首先,我们写一个Demo需要把准备工作做好

1.1创建5个文件,如图:

这里写图片描述

1.2在index.html中编写如下代码:
<html>
    <head>
        <title>留言表</title>
        <meta charset="UTF-8">
        <link rel="stylesheet" type="text/css" href="style.css">
    </head>
    <body>
        <div id="app" v-cloak style="width: 500px; margin: 0 auto;">
            <div class="message">

            </div>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
        <script src="input.js"></script>
        <script src="list.js"></script>
        <script src="index.js"></script>
    </body>
</html>
1.3在index.js中编写如下代码:
var app = new Vue({
    el:'#app',
});
1.4在input.js下变下如下代码:
//定义的组件
Vue.component('vInput',{

});

Vue.component('vTextarea',{

});
//稍后会重点介绍这个input.js的真正作用!
其他文件先不用添加代码,用到的时候我们再说!

2.如果要发布一条留言,需要的数据有昵称和留言内容,这些操作应该在Vue的实例中完成,所以在index.js中添加以下代码:

var app = new Vue({
    el:'#app',
    data:{
        username:'',
        message:'',
        list:[]
    },
    methods:{
        handleSend:function(){//给list添加一条留言数据
            this.list.push({
                name:this.username,
                message:this.message
            });
            this.message = '';//把textarea文本框置空
        }
    }
});
2.1在index.html中使用v-model将username和message进行双向绑定
<div class="message">
   <v-input v-model="username"></v-input>
   <v-textarea v-model="message"></v-textarea>
</div>
2.2在input.js中的v-input组件下添加如下代码.
Vue.component('vInput',{
    props:{
        value:{
          type:[String,Number],
          default:''
        }
    },
    render:function(h){
        var _this = this;
        return h('div',[
            h('span','昵称: '),
            h('input',{
                attrs:{
                    type:'text'
                },
                demProps:{
                    value:this.value
                },
                on:{
                    input:function(event){
                        _this.value = event.target.value;
                        _this.$emit('input',event.target.value);
                    }
                }
            })
        ]);
    }
});
扩充:组件与Vue的实例比较相似,需注册后才可以使用,注册有全局注册和局部注册俩中方式。全局注册后,
任何Vue实例都可以使用。全局注册代码如下:
Vue.component('my-component',{
    //选项
})
my_component就是注册的组件自定义的标签名称,要在父实例中使用这个组件,必须要在实例创建前注册,完后
就可以使用<my-component></my-component>来使用了,代码如下:
<div id="app">
  <my-component></my-component>
</div>
<script>
  Vue.component('my-component',{
      //选项
  });
  //在Vue实例创建之前完成了注册.
  var app = new Vue({
      el:'app',
  })
</script>

完后在组件中的选项那里添加template就可以显示内容了
Vue.component('my-component',{
      //选项
      template:'<div>组件的内容</div>'
  });
渲染后的结果就是:
<div id="app">
  <div>组件的内容</div>
</div>

$emit和JavaScript的观察者模式的dispatchEvent和addEventListener这俩个方法类似,
子组件$emit()用来触发事件,父组件$on()用来监听子组件的事件。父组件也可以直接在子组件的自定义标签上使用v-on来
监听子组件触发的自定义事件。

读完这段话,是不是对上面的代码又有了一个全新的认识呢!?
2.3列表数据list为空的时候,渲染一个”列表为空”的信息提示节点:不为空时,每个list-item要包含昵称,留言内容和恢复按钮3个子节点。list.js的render内容如下:
rander:function (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'
            }
        }, '留言列表为空!');
    }
}
2.4handleReply直接向父组件派发一个事件reply,父组件(app)接收后,将当前list-item的昵称提取,并设置到v-textarea内,在list.js中增加代码如下:
methods: {
        handleReply: function (index) {
            this.$emit('reply', index);
        }
    }
2.5在index.html中添加
<button @click="handleSend">发布</button>
 <list :list="list" @reply="handleReply"></list>
 具体代码如下:
<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"></list>
</div>
2.6因为需要判断一下用户是否输入的昵称和聊天的消息,所以我们在index.js中添加:
handleReply:function(index){
            var name = this.list[index].name;
            this.message = '回复@' + name +': ';
            this.$refs.message.focus();
        }

    if (this.username === '') {
                window.alert('请输入昵称!');
                return;
            }
            if (this.message === '') {
                window.alert('请输入消息!');
                return;
            }
2.7在input.js的vTextarea组件中添加:
render:function(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();
        }
    }

3.接下来我们就开始写css的样式了,在style.css中编写代码:

[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;
    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 #e3e8ee;
    overflow: hidden;
}
.list-item span{
    display: block;
    width: 60px;
    float: left;
    color: #39f;
}
.list-msg{
    display: block;
    margin-left: 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
}

4.这样就可以实现一个留言板了,五个页面所有代码,完整的我再发一遍

index.heml代码:

<html>
    <head>
        <title>留言表</title>
        <meta charset="UTF-8">
        <link rel="stylesheet" type="text/css" 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"></list>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
        <script src="input.js"></script>
        <script src="list.js"></script>
        <script src="index.js"></script>
    </body>
</html>

index.js代码:

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({
                name: this.username,
                message: this.message
            });
            this.message = '';
        },
        handleReply: function (index) {
            var name = this.list[index].name;
            this.message = '回复@' + name + ': ';
            this.$refs.message.focus();
        }
    }
});
input.js代码:

Vue.component('vInput', {
    props: {
        value: {
            type: [String, Number],
            default: ''
        }
    },
    render: function (h) {
        var _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) {
        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();
        }
    }
});


list.js代码:


Vue.component('list', {
    props: {
        list: {
            type: Array,
            default: function () {
                return [];
            }
        }
    },

    render: function (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);
        }
    }
});


style.css代码:

[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;
    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 #e3e8ee;
    overflow: hidden;
}
.list-item span{
    display: block;
    width: 60px;
    float: left;
    color: #39f;
}
.list-msg{
    display: block;
    margin-left: 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
}

最后,附上一张效果图:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_42382404/article/details/81741460