

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>留言列表</title>
<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;
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 #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;
}