一、小案例(评论区)

1、流程

(1)分析静态页面。(vue项目创建参考https://www.cnblogs.com/l-y-h/p/11241503.html)
(2)拆分静态页面,变成一个个组件。
(3)对组件编码,生成动态页面。

2、静态页面

参考来源:https://www.bilibili.com/video/av49099807/?p=22&t=1223

【举例:】
<!DOCTYPE html>
<html> <head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<!--此处如果bootstrap选用 4.3.1的版本,样式会无效(没去研究)-->
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/js/bootstrap.js"></script>
<title>vue_demo</title>
</head> <body>
<div id="app">
<div>
<!--头部-->
<header class="site-header jumbotron">
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>欢迎来到吐槽大厅</h1>
</div>
</div>
</div>
</header> <!--主体部分-->
<!--bootstrap将页面分为12格,此处拆分为左4格,右8格-->
<div class="container">
<div class="col-md-4">
<form action="form-horizontal">
<div class="form-group">
<label>用户名</label>
<input type="text" class="form-control" placeholder="用户名">
</div>
<div class="form-group">
<label>吐槽内容</label>
<textarea type="text" class="form-control" placeholder="吐槽内容"></textarea>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="button" class="btn btn-default pull-right">提交</button>
</div>
</div>
</form>
</div>
<!--md4 for Add end --> <div class="col-md-8">
<h3 class="reply">吐槽回复:</h3>
<h2>暂无吐槽,点击左侧添加吐槽吧!</h2>
<ul class="list-group">
<li class="list-group-item">
<div class="handle col-sm-offset-2 col-sm-10">
<a class="pull-right">删除</a>
</div>
<p class="user"><span>Tom</span><span>说:</span></p>
</li>
<li class="list-group-item">
<div class="handle col-sm-offset-2 col-sm-10">
<a class="pull-right">删除</a>
</div>
<p class="user"><span>Tom</span><span>说:</span></p>
</li>
</ul>
</div>
<!--md8 for List end -->
</div>
</div>
</div>
<!--app -->
</body> </html>

页面截图:

3、拆分静态页面,

拆分静态页面,使其变成一个个静态组件。

Step1:是一个大的组件(App),里面包含各种组件。

Step2:页面内容可以拆分成 提交吐槽组件(Comment),吐槽回复组件(Comments)。

Step3:吐槽回复组件里面 可以对 每一条吐槽进行拆分,即每个吐槽为一个组件(Item)。

文件结构如下:

【主要文件与文件夹:】
index.html 主页面,所有组件操作均为其服务,在此处引入css、js文件
main.js vue入口文件,从此处启动vue
App.vue App.vue组件,项目的入口组件
components 里面保存各个小组件 【index.html】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!--所有组件都是为index.html服务的,所以在此处引入css、js文件-->
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
<title>vuedemo</title>
</head>
<body>
<noscript>
<strong>We're sorry but vuedemo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html> 【main.js】
import Vue from 'vue'
import App from './App.vue' Vue.config.productionTip = false new Vue({
render: h => h(App),
}).$mount('#app') 【App.vue】
<template>
<div>
<!--头部-->
<header class="site-header jumbotron">
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>欢迎来到吐槽大厅</h1>
</div>
</div>
</div>
</header> <!--主体部分-->
<!--bootstrap将页面分为12格,此处拆分为左4格,右8格-->
<div class="container">
<!--使用各组件-->
<Comment></Comment>
<Comments></Comments>
</div>
</div>
<!--App -->
</template> <script>
// 引入各组件
import Comment from './components/Comment.vue'
import Comments from './components/Comments.vue' export default {
name: 'app',
// 注册各组件
components: {
Comment,
Comments
}
}
</script> <style>
</style> 【Comment.vue】
<template>
<div class="col-md-4">
<form action="form-horizontal">
<div class="form-group">
<label>用户名</label>
<input type="text" class="form-control" placeholder="用户名">
</div>
<div class="form-group">
<label>吐槽内容</label>
<textarea type="text" class="form-control" placeholder="吐槽内容"></textarea>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="button" class="btn btn-default pull-right">提交</button>
</div>
</div>
</form>
</div>
<!--Comment -->
</template> <script>
export default{
name: 'comment'
}
</script> <style> </style> 【Comments.vue】
<template>
<div class="col-md-8">
<h3 class="reply">吐槽回复:</h3>
<h2>暂无吐槽,点击左侧添加吐槽吧!</h2>
<ul class="list-group">
<Item></Item>
</ul>
</div>
<!--md8 for List end -->
</template> <script>
import Item from './Item.vue' export default{
name: 'comments',
components: {
Item
}
}
</script> <style> </style> 【Item.vue】
<template>
<!--注意,需要使用div包裹,否则会报错-->
<div>
<li class="list-group-item">
<div class="handle col-sm-offset-2 col-sm-10">
<a class="pull-right">删除</a>
</div>
<p class="user"><span>Tom</span><span>说:</span></p>
</li>
<li class="list-group-item">
<div class="handle col-sm-offset-2 col-sm-10">
<a class="pull-right">删除</a>
</div>
<p class="user"><span>Tom</span><span>说:</span></p>
</li>
</div>
</template> <script>
export default{
name: 'item'
}
</script> <style> </style>

拆分后效果与原静态页面一致。

4、组件间值的传递(组件间通信)

  静态页面上吐槽区的内容不会是写好的,是动态生成的,那么如何生成,就涉及到组件间的值的传递。通过props 来声明属性,使用data来传递数据(属性值),使用 v-bind 绑定属性。

【对上面代码进行修改】
App.vue 获取数据,将数据往吐槽区(Comments.vue)传
Comments.vue 接收App.vue传来的数据,将每条数据往Item.vue传
Item.vue 接收Comments.vue传来的数据并显示 要是一眼看不出来,可以下载个Bcompare软件,自行比较一下代码间的区别。 【App.vue】
<template>
<div>
<!--头部-->
<header class="site-header jumbotron">
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>欢迎来到吐槽大厅</h1>
</div>
</div>
</div>
</header> <!--主体部分-->
<!--bootstrap将页面分为12格,此处拆分为左4格,右8格-->
<div class="container">
<!--使用各组件-->
<Comment></Comment>
<!--需使用v-bind绑定属性-->
<Comments :contents="contents"></Comments>
</div>
</div>
<!--App -->
</template> <script>
// 引入各组件
import Comment from './components/Comment.vue'
import Comments from './components/Comments.vue' export default {
name: 'app',
// 注册各组件
components: {
Comment,
Comments
}, // 传递数据
data(){
return {
contents:[
{name: 'tom', content: '妈妈,我想吃烤山药'},
{name: 'jarry', content: '吃,吃大块的'},
{name: 'jarry', content: '两块够不'},
{name: 'tom', content: '够了,妈妈真好,谢谢妈妈'},
]
}
}
}
</script> <style>
</style> 【Comments.vue】
<template>
<div class="col-md-8">
<h3 class="reply">吐槽回复:</h3>
<ul class="list-group">
<Item v-for="(content, index) in contents" :key="index" :content="content"></Item>
</ul>
</div>
<!--md8 for List end -->
</template> <script>
import Item from './Item.vue' export default{
name: 'comments',
// 声明接收属性,此属性可以在该组件中使用
props: ['contents'], // 只指定属性名 // 注册组件
components: {
Item
}
}
</script> <style> </style> 【Item.vue】
<template>
<!--注意,需要使用div包裹,否则会报错-->
<div>
<li class="list-group-item">
<div class="handle col-sm-offset-2 col-sm-10">
<a class="pull-right">删除</a>
</div>
<p class="user"><span style="font-size: 18px;">{{content.name}}</span><span style="font-size: 18px;">说:</span>{{content.content}}</p>
</li>
</div>
</template> <script>
export default{
name: 'item',
props: {
// 指定属性名以及属性值的类型
content : Object
}
}
</script> <style> </style>

效果如下图:

5、动态交互--添加

  实现添加吐槽操作。

  使用v-on 绑定事件,使用v-model 实现数据的双向绑定,方法也可以使用 v-bind 绑定 并进行组件通信。

【对上面代码进行修改】
App.vue 定义增加吐槽的方法,并作为属性传递给Comment.vue组件
Comment.vue 接收属性,并定义添加数据的事件 【App.vue】
<template>
<div>
<!--头部-->
<header class="site-header jumbotron">
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>欢迎来到吐槽大厅</h1>
</div>
</div>
</div>
</header> <!--主体部分-->
<!--bootstrap将页面分为12格,此处拆分为左4格,右8格-->
<div class="container">
<!--使用各组件-->
<Comment :addComment="addComment"></Comment>
<!--需使用v-bind绑定属性-->
<Comments :contents="contents"></Comments>
</div>
</div>
<!--App -->
</template> <script>
// 引入各组件
import Comment from './components/Comment.vue'
import Comments from './components/Comments.vue' export default {
name: 'app',
// 注册各组件
components: {
Comment,
Comments
}, // 传递数据
data(){
return {
contents:[
{name: 'tom', content: '妈妈,我想吃烤山药'},
{name: 'jarry', content: '吃,吃大块的'},
{name: 'jarry', content: '两块够不'},
{name: 'tom', content: '够了,妈妈真好,谢谢妈妈'},
]
}
}, // 操作数据的方法
methods: {
addComment(comment){
// 在数组头部插入数据
this.contents.unshift(comment);
}
}
}
</script> <style>
</style> 【Comment.vue】
<template>
<div class="col-md-4">
<form action="form-horizontal">
<div class="form-group">
<label>用户名</label>
<input type="text" class="form-control" placeholder="用户名" v-model="name">
</div>
<div class="form-group">
<label>吐槽内容</label>
<textarea type="text" class="form-control" placeholder="吐槽内容" v-model="content"></textarea>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="button" class="btn btn-default pull-right" @click="add">提交</button>
</div>
</div>
</form>
</div>
<!--Comment -->
</template> <script>
export default{
name: 'comment',
data(){
return {
name : '',
content : ''
}
},
props:{
// 定义属性类型、属性值类型、必须性
addComment: {
type: Function,
required: true
}
},
methods: {
add(){
// step1:进行合法性检验
const name = this.name.trim();
const content = this.content.trim();
if(!name || !content){
alert("输入内容不能为空");
return;
} // step2:将name,content封装成一个comment(吐槽)对象
const comment = {name, content}; console.log(comment);
// step3: 将comment 加入到 comments(吐槽区)
this.addComment(comment); // step4:清空输入框
this.name = '';
this.content = '';
}
}
}
</script> <style> </style>

效果:

6、动态交互--删除

  进行删除操作。

  类似于添加操作。

【对上面文件进行修改】
App.vue 定义删除数据的方法,并将其作为属性传递给Comments.vue
Comments.vue 作为一个中间的组件,传递index以及删除方法
Item.vue 接收Comments.vue传递的属性,并定义删除事件 【App.vue】
<template>
<div>
<!--头部-->
<header class="site-header jumbotron">
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>欢迎来到吐槽大厅</h1>
</div>
</div>
</div>
</header> <!--主体部分-->
<!--bootstrap将页面分为12格,此处拆分为左4格,右8格-->
<div class="container">
<!--使用各组件-->
<Comment :addComment="addComment"></Comment>
<!--需使用v-bind绑定属性-->
<Comments :contents="contents" :deleteComment="deleteComment"></Comments>
</div>
</div>
<!--App -->
</template> <script>
// 引入各组件
import Comment from './components/Comment.vue'
import Comments from './components/Comments.vue' export default {
name: 'app',
// 注册各组件
components: {
Comment,
Comments
}, // 传递数据
data(){
return {
contents:[
{name: 'tom', content: '妈妈,我想吃烤山药'},
{name: 'jarry', content: '吃,吃大块的'},
{name: 'jarry', content: '两块够不'},
{name: 'tom', content: '够了,妈妈真好,谢谢妈妈'},
]
}
}, // 操作数据的方法
methods: {
addComment(comment){
// 在数组头部插入数据
this.contents.unshift(comment);
},
deleteComment(index){
// 删除指定下标的数据
this.contents.splice(index, 1);
}
}
}
</script> <style>
</style> 【Comments.vue】
<template>
<div class="col-md-8">
<h3 class="reply">吐槽回复:</h3>
<h3 v-show="contents.length === 0">暂无吐槽,点击左侧提交吐槽!!!</h3>
<ul class="list-group">
<Item v-for="(content, index) in contents" :key="index" :content="content" :deleteComment="deleteComment" :index="index"></Item>
</ul>
</div>
<!--md8 for List end -->
</template> <script>
import Item from './Item.vue' export default {
name: 'comments',
// 声明接收属性,此属性可以在该组件中使用
props: ['contents', 'deleteComment'], // 只指定属性名 // 注册组件
components: {
Item
}
}
</script> <style> </style> 【Item.vue】
<template>
<!--注意,需要使用div包裹,否则会报错-->
<div>
<li class="list-group-item">
<div class="handle col-sm-offset-2 col-sm-10">
<a class="pull-right" @click="deleteItem">删除</a>
</div>
<p class="user"><span style="font-size: 18px;">{{content.name}}</span><span style="font-size: 18px;">说:</span>{{content.content}}</p>
</li>
</div>
</template> <script>
export default{
name: 'item',
props: {
// 指定属性名以及属性值的类型
content : Object,
deleteComment : Function,
index : Number
},
methods: {
deleteItem() {
const {content, deleteComment, index} = this;
// 使用 反引号 + ${}, ES6模板字符串
if(window.confirm(`确定删除${content.name}的评论吗?`)){
deleteComment(index);
}
}
}
}
</script> <style> </style>

运行结果:

7、完整代码

(1)项目结构以及修改的文件

(2)代码

【index.html】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!--所有组件都是为index.html服务的,所以在此处引入css、js文件-->
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
<title>vuedemo</title>
</head>
<body>
<noscript>
<strong>We're sorry but vuedemo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html> 【main.js】
import Vue from 'vue'
import App from './App.vue' Vue.config.productionTip = false new Vue({
render: h => h(App),
}).$mount('#app') 【App.vue】
<template>
<div>
<!--头部-->
<header class="site-header jumbotron">
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>欢迎来到吐槽大厅</h1>
</div>
</div>
</div>
</header> <!--主体部分-->
<!--bootstrap将页面分为12格,此处拆分为左4格,右8格-->
<div class="container">
<!--使用各组件-->
<Comment :addComment="addComment"></Comment>
<!--需使用v-bind绑定属性-->
<Comments :contents="contents" :deleteComment="deleteComment"></Comments>
</div>
</div>
<!--App -->
</template> <script>
// 引入各组件
import Comment from './components/Comment.vue'
import Comments from './components/Comments.vue' export default {
name: 'app',
// 注册各组件
components: {
Comment,
Comments
}, // 传递数据
data(){
return {
contents:[
{name: 'tom', content: '妈妈,我想吃烤山药'},
{name: 'jarry', content: '吃,吃大块的'},
{name: 'jarry', content: '两块够不'},
{name: 'tom', content: '够了,妈妈真好,谢谢妈妈'},
]
}
}, // 操作数据的方法
methods: {
addComment(comment){
// 在数组头部插入数据
this.contents.unshift(comment);
},
deleteComment(index){
// 删除指定下标的数据
this.contents.splice(index, 1);
}
}
}
</script> <style>
</style> 【Comment.vue】
<template>
<div class="col-md-4">
<form action="form-horizontal">
<div class="form-group">
<label>用户名</label>
<input type="text" class="form-control" placeholder="用户名" v-model="name">
</div>
<div class="form-group">
<label>吐槽内容</label>
<textarea type="text" class="form-control" placeholder="吐槽内容" v-model="content"></textarea>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="button" class="btn btn-default pull-right" @click="add">提交</button>
</div>
</div>
</form>
</div>
<!--Comment -->
</template> <script>
export default{
name: 'comment',
data(){
return {
name : '',
content : ''
}
},
props:{
// 定义属性类型、属性值类型、必须性
addComment: {
type: Function,
required: true
}
},
methods: {
add(){
// step1:进行合法性检验
const name = this.name.trim();
const content = this.content.trim();
if(!name || !content){
alert("输入内容不能为空");
return;
} // step2:将name,content封装成一个comment(吐槽)对象
const comment = {name, content}; console.log(comment);
// step3: 将comment 加入到 comments(吐槽区)
this.addComment(comment); // step4:清空输入框
this.name = '';
this.content = '';
}
}
}
</script> <style> </style> 【Comments.vue】
<template>
<div class="col-md-8">
<h3 class="reply">吐槽回复:</h3>
<h3 v-show="contents.length === 0">暂无吐槽,点击左侧提交吐槽!!!</h3>
<ul class="list-group">
<Item v-for="(content, index) in contents" :key="index" :content="content" :deleteComment="deleteComment" :index="index"></Item>
</ul>
</div>
<!--md8 for List end -->
</template> <script>
import Item from './Item.vue' export default {
name: 'comments',
// 声明接收属性,此属性可以在该组件中使用
props: ['contents', 'deleteComment'], // 只指定属性名 // 注册组件
components: {
Item
}
}
</script> <style> </style> 【Item.vue】
<template>
<!--注意,需要使用div包裹,否则会报错-->
<div>
<li class="list-group-item">
<div class="handle col-sm-offset-2 col-sm-10">
<a class="pull-right" @click="deleteItem">删除</a>
</div>
<p class="user"><span style="font-size: 18px;">{{content.name}}</span><span style="font-size: 18px;">说:</span>{{content.content}}</p>
</li>
</div>
</template> <script>
export default{
name: 'item',
props: {
// 指定属性名以及属性值的类型
content : Object,
deleteComment : Function,
index : Number
},
methods: {
deleteItem() {
const {content, deleteComment, index} = this;
// 使用 反引号 + ${}, ES6模板字符串
if(window.confirm(`确定删除${content.name}的评论吗?`)){
deleteComment(index);
}
}
}
}
</script> <style> </style>

运行结果此处不再重复截图,与上述截图相同。

最新文章

  1. NFS
  2. MYSQL 常用函数(数学、字符串、日期时间、系统信息、加密)
  3. 游戏BUFF设计
  4. SQL Server基础
  5. Web性能压力测试工具之Siege详解
  6. poj 1940 Wine Trading in Gergovia_贪心
  7. oschina图形和图像工具开源软件
  8. Linux下查看USB设备的VID、PID命令
  9. 基于HTML5 Canvas 实现弹出框
  10. vs2015添加ActiveX Control Test Container工具(转载)
  11. 大学java教案之MySQL安装图解
  12. Confluence 6 删除垃圾内容
  13. 1.1:Get Started with Unity Shaders
  14. C#遍历类的属性,然后给其赋值
  15. float四舍五入保留一位小数点(坑)
  16. Node.js实战(九)之事件循环
  17. 网站精准查询IP
  18. Struts2框架学习
  19. laravel模型中打印sql语句
  20. zoj 2615 Cells 栈的运用

热门文章

  1. mySql中The user specified as a definer (&#39;root&#39;@&#39;%&#39;) does not exist
  2. ASP.NET CORE 使用Consul实现服务治理与健康检查(2)——源码篇
  3. ASP.NET MVC项目中EntityFramework&quot;代码优先方法&quot;的使用步骤
  4. Java连载61-异常的机制与分类
  5. Python高级特性——列表生成式(list Comprehensions)
  6. Python高级特性——切片(Slice)
  7. Java生鲜电商平台-高可用微服务系统如何设计?
  8. 大数据环境下mongoDB要加索引
  9. node error SOCKET error:10106
  10. 由“RangeError: Invalid status code: 0”错误所引发的思考