目录
1. 基于脚手架编写项目
打开vue_demo
1.1 初始化显示
组件之间的通信 props
App.vue
template 内是它负责的部分
script 引入其他组件 import component
<!-- -->
<template>
<div>
<header class="site-header jumbotron">
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>请发表对Vue的评论</h1>
</div>
</div>
</div>
</header>
<div class="container">
<Add/>
<List :comments="comments"/>
</div>
</div>
</template>
<script>
import Add from './components/Add.vue'
import List from './components/List.vue'
export default {
data(){
return {
comments:[
{
name:'张三',
content:'Vue soso'
},
{
name:'张王',
content:'Vue easy'
},
{
name:'张飞',
content:'Vue good'
}
]
}
},
components: {
Add,List
}
};
</script>
<style>
</style>
Add.vue
<!-- -->
<template>
<div class="col-md-4">
<form class="form-horizontal">
<div class="form-group">
<label>用户名</label>
<input type="text" class="form-control" placeholder="用户名">
</div>
<div class="form-group">
<label>评论内容</label>
<textarea class="form-control" rows="6" 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>
</template>
<script>
export default {
};
</script>
<style>
</style>
List.vue
接收 属性值 comments
引入声明其他组件item
<!-- -->
<template>
<div class="col-md-8">
<h3 class="reply">评论回复:</h3>
<h2 style='display: none'>暂无评论,点击左侧添加评论!!!</h2>
<ul class="list-group">
<Item :comment="comment" v-for="(comment,index) in comments" :key="index"/>
</ul>
</div>
</template>
<script>
import Item from './Item.vue'
export default {
//声明接收属性:这个属性就是成为组件对象的属性
props:['comments'],//只指定属性名
components: {
Item
}
};
</script>
<style>
.reply {
margin-top: 0px;
}
</style>
Item.vue
<!-- -->
<template>
<div>
<li class="list-group-item">
<div class="handle">
<a href="javascript:;">删除</a>
</div>
<p class="user"><span >{{comment.name}}</span><span>说:</span></p>
<p class="centence">{{comment.content}}</p>
</li>
</div>
</template>
<script>
export default {
props: {
comment:Object//指定属性名和属性值类型
}
};
</script>
<style>
li {
transition: .5s;
overflow: hidden;
}
.handle {
width: 40px;
border: 1px solid #ccc;
background: #fff;
position: absolute;
right: 10px;
top: 1px;
text-align: center;
}
.handle a {
display: block;
text-decoration: none;
}
.list-group-item .centence {
padding: 0px 50px;
}
.user {
font-size: 22px;
}
</style>
1.2 交互添加
数据在那个组件,更新数据的行为(方法)就该在那个组件
App.vue
<!-- -->
<template>
<div>
<header class="site-header jumbotron">
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>请发表对Vue的评论</h1>
</div>
</div>
</div>
</header>
<div class="container">
<Add :addComment="addComment"/>
<List :comments="comments"/>
</div>
</div>
</template>
<script>
import Add from './components/Add.vue'
import List from './components/List.vue'
export default {
data(){
return {
comments:[//数据在那个组件更新数据的行为就该在那个组件
{
name:'张三',
content:'Vue soso'
},
{
name:'张王',
content:'Vue easy'
},
{
name:'张飞',
content:'Vue good'
}
]
}
},
methods: {
addComment(comment){
this.comments.unshift(comment)
}
},
components: {
Add,List
}
};
</script>
<style>
</style>
props: {
addComment:{//指定属性名/属性值类型/必要性
type:Function,
required:true
}
},
Add.vue
<!-- -->
<template>
<div class="col-md-4">
<form class="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 class="form-control" rows="6" 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>
</template>
<script>
export default {
props: {
addComment:{//指定属性名/属性值类型/必要性
type:Function,
required:true
}
},
data () {
return {
name:'',
contentt:''
}
},
methods: {
add(){
//1.检查输入内容的合法性
const name=this.name.trim()
const content=this.content.trim()
if(!name||!content)
{
alert('姓名或内容不为空')
return
}
//2.根据输入的内容封装成comment对象
const comment={
name,
content
}
//3.添加到comments
this.addComment(comment)
//4.清除输入
this.name=''
this.content=''
}
}
};
</script>
<style>
</style>
1.3 删除
在App中实现删除方法 之后传递到list里面
<!-- -->
<template>
<div>
<header class="site-header jumbotron">
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>请发表对Vue的评论</h1>
</div>
</div>
</div>
</header>
<div class="container">
<Add :addComment="addComment"/>
<List :comments="comments" :deleteComment="deleteComment"/>
</div>
</div>
</template>
<script>
import Add from './components/Add.vue'
import List from './components/List.vue'
export default {
data(){
return {
comments:[//数据在那个组件更新数据的行为就该在那个组件
{
name:'张三',
content:'Vue soso'
},
{
name:'张王',
content:'Vue easy'
},
{
name:'张飞',
content:'Vue good'
}
]
}
},
methods: {
//添加评论
addComment(comment){
this.comments.unshift(comment)
},
//删除指定下标评论
deleteComment(index)
{
this.comments.splice(index,1)
}
},
components: {
Add,List
}
};
</script>
<style>
</style>
List中声明传递的方法,再向item传递方法下标
重点看item标签
<!-- -->
<template>
<div class="col-md-8">
<h3 class="reply">评论回复:</h3>
<h2 v-show="comments.length==0">暂无评论,点击左侧添加评论!!!</h2>
<ul class="list-group">
<Item :comment="comment" v-for="(comment,index) in comments" :key="index" :deleteComment="deleteComment" :index="index"/>
</ul>
</div>
</template>
<script>
import Item from './Item.vue'
export default {
//声明接收属性:这个属性就是成为组件对象的属性
props:['comments','deleteComment'],//只指定属性名
components: {
Item
}
};
</script>
<style>
.reply {
margin-top: 0px;
}
</style>
item中实现deleteItem方法调用的是deleteComment方法,声明传递过来的东西
<!-- -->
<template>
<div>
<li class="list-group-item">
<div class="handle">
<a href="javascript:;" @click="deleteItem">删除</a>
</div>
<p class="user"><span >{{comment.name}}</span><span>说:</span></p>
<p class="centence">{{comment.content}}</p>
</li>
</div>
</template>
<script>
export default {
props: {
comment:Object,//指定属性名和属性值类型
deleteComment:Function,
index:Number
},
methods: {
deleteItem(){
const{comment,index,deleteComment}=this
if(window.confirm(`确定删除${comment.name}的评论吗?`))
{
this.deleteComment(index)
}
}
}
};
</script>
<style>
li {
transition: .5s;
overflow: hidden;
}
.handle {
width: 40px;
border: 1px solid #ccc;
background: #fff;
position: absolute;
right: 10px;
top: 1px;
text-align: center;
}
.handle a {
display: block;
text-decoration: none;
}
.list-group-item .centence {
padding: 0px 50px;
}
.user {
font-size: 22px;
}
</style>
2.案例二
2.1 初始化显示
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>React App</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div id="root">
<div class="todo-container">
<div class="todo-wrap">
<div class="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车键确认"/>
</div>
<ul class="todo-main">
<li>
<label>
<input type="checkbox"/>
<span>xxxxx</span>
</label>
<button class="btn btn-danger" style="display:none">删除</button>
</li>
<li>
<label>
<input type="checkbox"/>
<span>yyyy</span>
</label>
<button class="btn btn-danger" style="display:none">删除</button>
</li>
</ul>
<div class="todo-footer">
<label>
<input type="checkbox"/>
</label>
<span>
<span>已完成0</span> / 全部2
</span>
<button class="btn btn-danger">清除已完成任务</button>
</div>
</div>
</div>
</div>
</body>
</html>
将其划分成五部分:
App.vue
导入其他组件 写入标签 初始化数据 将数据传到List
<!-- -->
<template>
<div id="root">
<div class="todo-container">
<div class="todo-wrap">
<Header />
<Footer />
<List :todos="todos"/>
</div>
</div>
</div>
</template>
<script>
import Header from "./components/Header.vue";
import Footer from "./components/Footer.vue";
import List from "./components/List.vue";
export default {
data() {
return {
todos: [
{ title: "写英语", complete: false },
{ title: "读语文", complete: false },
{ title: "打球", complete: false },
{ title: "理发", complete: false },
],
};
},
components: {
Header,
Footer,
List,
},
};
</script>
<style>
.todo-container {
width: 600px;
margin: 0 auto;
}
.todo-container .todo-wrap {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
</style>
List.vue
声明传来的数据 声明组件item 导入 写标签 传值
<!-- -->
<template>
<ul class="todo-main">
<Item v-for="(todo,index) in todos" :key="index" :todo="todo" :index="index"/>
</ul>
</template>
<script>
import Item from './Item.vue'
export default
{
props:
{
todos:Array
},
components: {
Item
}
}
</script>
<style>
.todo-main {
margin-left: 0px;
border: 1px solid #ddd;
border-radius: 2px;
padding: 0px;
}
.todo-empty {
height: 40px;
line-height: 40px;
border: 1px solid #ddd;
border-radius: 2px;
padding-left: 5px;
margin-top: 10px;
}
</style>
<!-- -->
<template>
<li>
<label>
<input type="checkbox" v-model="todo.complete"/>
<span>{{todo.title}}</span>
</label>
<button class="btn btn-danger" style="display:none">删除</button>
</li>
</template>
<script>
export default {
props: {
todo:Object,
index:Number
}
}
</script>
<style>
/*item*/
li {
list-style: none;
height: 36px;
line-height: 36px;
padding: 0 5px;
border-bottom: 1px solid #ddd;
}
li label {
float: left;
cursor: pointer;
}
li label li input {
vertical-align: middle;
margin-right: 6px;
position: relative;
top: -1px;
}
li button {
float: right;
display: none;
margin-top: 3px;
}
li:before {
content: initial;
}
li:last-child {
border-bottom: none;
}
</style>
2.2 添加
首先在App中 写一个方法是用来添加数据的 之后传到Header中
<!-- -->
<template>
<div id="root">
<div class="todo-container">
<div class="todo-wrap">
<Header :addTodo="addTodo"/>
<List :todos="todos"/>
<Footer />
</div>
</div>
</div>
</template>
<script>
import Header from "./components/Header.vue";
import Footer from "./components/Footer.vue";
import List from "./components/List.vue";
export default {
data() {
return {
todos: [
{ title: "写英语", complete: false },
{ title: "读语文", complete: false },
{ title: "打球", complete: false },
{ title: "理发", complete: false },
],
};
},
components: {
Header,
Footer,
List,
},
methods: {
addTodo(todo){
this.todos.unshift(todo)
}
}
};
</script>
<style>
.todo-container {
width: 600px;
margin: 0 auto;
}
.todo-container .todo-wrap {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
</style>
在header中需要声明 传递来的方法 之后给input添加数据绑定 title 加上监听事件 ,实现add方法
<!-- -->
<template>
<div class="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="addItem" />
</div>
</template>
<script>
export default
{
props: {
addTodo:Function
},
data () {
return {
title:''
}
},
methods: {
addItem(){
//检查输入的合法性
const title=this.title.trim()
if(!title)
{
alert('不能为空')
return
}
//生成todo对象
const todo={
title,complete:false
}
//添加到数组中
this.addTodo(todo)
//清除输入
this.title=''
}
}
}
</script>
<style>
.todo-header input {
width: 560px;
height: 28px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 4px;
padding: 4px 7px;
}
.todo-header input:focus {
outline: none;
border-color: rgba(82, 168, 236, 0.8);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),
0 0 8px rgba(82, 168, 236, 0.6);
}
</style>
2.3 删除
首先 当鼠标移入到item时 显示出来删除按钮切背景颜色改变
<li @mouseenter="handleShow(true)" @mouseleave="handleShow(false)"
:style="{background:bgColor}">
methods: {
handleShow(isEnter)
{
if(isEnter)
{
this.bgColor='rgb(217,220,217)'
this.isShow=true;
}else
{
this.bgColor='white'
this.isShow=false;
}
}
}
其次给删除按钮绑定删除事件
<button class="btn btn-danger" v-show="isShow" @click="deleteItem">删除</button>
要想删除 首先在 App里面实现删除 并传递到list-item
<List :todos="todos" :deleteTodo="deleteTodo"/>
methods:
{
deleteTodo(index)
{
this.todos.splice(index,1)
}
}
在item中实现删除方法
deleteItem()
{
const {todo,index,deleteTodo}=this
if(window.confirm(`确认删除${todo.title}?`))
{
deleteTodo(index)
}
}
item.vue
<!-- -->
<template>
<li @mouseenter="handleShow(true)" @mouseleave="handleShow(false)" :style="{background:bgColor}">
<label>
<input type="checkbox" v-model="todo.complete"/>
<span>{{todo.title}}</span>
</label>
<button class="btn btn-danger" v-show="isShow" @click="deleteItem">删除</button>
</li>
</template>
<script>
export default {
props: {
todo:Object,
index:Number,
deleteTodo:Function
},
data () {
return {
bgColor:'white',
isShow:false
}
},
methods: {
handleShow(isEnter)
{
if(isEnter)
{
this.bgColor='rgb(217,220,217)'
this.isShow=true;
}else{
this.bgColor='white'
this.isShow=false;
}
},
deleteItem()
{
const {todo,index,deleteTodo}=this
if(window.confirm(`确认删除${todo.title}?`))
{
deleteTodo(index)
}
}
}
}
</script>
<style>
/*item*/
li {
list-style: none;
height: 36px;
line-height: 36px;
padding: 0 5px;
border-bottom: 1px solid #ddd;
}
li label {
float: left;
cursor: pointer;
}
li label li input {
vertical-align: middle;
margin-right: 6px;
position: relative;
top: -1px;
}
li button {
float: right;
display: none;
margin-top: 3px;
}
li:before {
content: initial;
}
li:last-child {
border-bottom: none;
}
</style>
List.vue
<!-- -->
<template>
<ul class="todo-main">
<Item v-for="(todo,index) in todos" :key="index" :todo="todo" :index="index" :deleteTodo="deleteTodo"/>
</ul>
</template>
<script>
import Item from './Item.vue'
export default
{
props:
{
todos:Array,
deleteTodo:Function
},
components: {
Item
}
}
</script>
<style>
.todo-main {
margin-left: 0px;
border: 1px solid #ddd;
border-radius: 2px;
padding: 0px;
}
.todo-empty {
height: 40px;
line-height: 40px;
border: 1px solid #ddd;
border-radius: 2px;
padding-left: 5px;
margin-top: 10px;
}
</style>
App.vue
<!-- -->
<template>
<div id="root">
<div class="todo-container">
<div class="todo-wrap">
<Header :addTodo="addTodo"/>
<List :todos="todos" :deleteTodo="deleteTodo"/>
<Footer />
</div>
</div>
</div>
</template>
<script>
import Header from "./components/Header.vue";
import Footer from "./components/Footer.vue";
import List from "./components/List.vue";
export default {
data() {
return {
todos: [
{ title: "写英语", complete: false },
{ title: "读语文", complete: false },
{ title: "打球", complete: false },
{ title: "理发", complete: false },
],
};
},
components: {
Header,
Footer,
List,
},
methods: {
addTodo(todo){
this.todos.unshift(todo)
},
deleteTodo(index){
this.todos.splice(index,1)
}
}
};
</script>
<style>
.todo-container {
width: 600px;
margin: 0 auto;
}
.todo-container .todo-wrap {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
</style>
2.4 Footer组件功能
实现全选功能以及清楚已选得任务
Footer.vue
<!-- -->
<template>
<div class="todo-footer">
<label>
<input type="checkbox" v-model="allCheck"/>
</label>
<span>
<span>已完成{{completeNum}}</span> / 全部{{todos.length}}
</span>
<button class="btn btn-danger" v-show="completeNum" @click="deleteCompleteTodos ">清除已完成任务</button>
</div>
</template>
<script>
export default {
props: {
todos:Array,
deleteCompleteTodos:Function,
selectAll:Function
},
computed: {
completeNum()
{
//这部分的函数有疑问
return this.todos.reduce((preTotal,todo)=>preTotal+(todo.complete?1:0),0)
},
allCheck:{
get(){
return this.completeNum==this.todos.length&&this.completeNum>0
},set(value){
this.selectAll(value)
}
}
}
}
</script>
<style>
.todo-footer {
height: 40px;
line-height: 40px;
padding-left: 6px;
margin-top: 5px;
}
.todo-footer label {
display: inline-block;
margin-right: 20px;
cursor: pointer;
}
.todo-footer label input {
position: relative;
top: -1px;
vertical-align: middle;
margin-right: 5px;
}
.todo-footer button {
float: right;
margin-top: 5px;
}
</style>
App.vue
<!-- -->
<template>
<div id="root">
<div class="todo-container">
<div class="todo-wrap">
<Header :addTodo="addTodo"/>
<List :todos="todos" :deleteTodo="deleteTodo"/>
<Footer :todos="todos" :deleteCompleteTodos="deleteCompleteTodos" :selectAll="selectAll"/>
</div>
</div>
</div>
</template>
<script>
import Header from "./components/Header.vue";
import Footer from "./components/Footer.vue";
import List from "./components/List.vue";
export default {
data() {
return {
todos: [
{ title: "写英语", complete: false },
{ title: "读语文", complete: false },
{ title: "打球", complete: false },
{ title: "理发", complete: false },
],
};
},
components: {
Header,
Footer,
List,
},
methods: {
addTodo(todo){
this.todos.unshift(todo)
},
deleteTodo(index){
this.todos.splice(index,1)
},
deleteCompleteTodos (){
this.todos=this.todos.filter(todo=>!todo.complete)
},
selectAll(check){
this.todos.forEach(todo=>(todo.complete=check))
}
}
};
</script>
<style>
.todo-container {
width: 600px;
margin: 0 auto;
}
.todo-container .todo-wrap {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
</style>