<!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的小组件写下来,写的我真的好佩服尤大...
<!DOCTYPEhtml> <htmllang="en"> <head> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width, initial-scale=1.0"> <metahttp-equiv="X-UA-Compatible"content="ie=edge"> <title>Document</title> <scriptsrc="Vue.2.6.10.js"></script> </head> <style> [v-cloak]{ display: none; } *{ padding: 0; margin: 0; } .message{ width: 450px; text-align: right; } .messagediv{ margin-bottom: 12px; } .messagespan{ display: inline-block; width: 100px; vertical-align: top; } .messageinput, .messagetextarea{ width: 300px; height: 32px; padding: 0 6px; color:#657180; border: 1px solid #d7dde4; border-radius: 4px; cursor: text; outline: none; } .messageinput:focus, .messagetextarea:focus{ border: 1px solid #3399ff; } .messagetextarea{ height: 60px; padding: 4px 6px; } .messagebutton{ 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-itemspan{ display: block; width: 60px; float: left; color:#39f; } .list-msg{ display: block; width: 60px; text-align: justify; } .list-msga{ color: #9ea7b4; cursor: pointer; float: right;} .list-msga:hover{ color:#39f; } .list-nothing{ text-align: center; color:#9ea7b4; padding: 20px;
}
</style> <body> <divid="app"v-cloakstyle="width: 500px;margin:0 auto; margin-top: 30px;"> <divclass="message"> <v-inputv-model='username'></v-input> <v-textareav-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; returnh('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; returnh('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){ returnh('div',{ attrs:{ class:'list' }, },list); }else{ returnh('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>