该项目包含了bootstrap的巨幕、标签页、模态框、vue的组件及父子组件传值等知识。
首先,整个页面分为两大部分:
- 左侧的个人信息部分
- 右侧的正文部分:正文部分包含了三个方面:日记、游记、相片集
个人信息部分
该部分的背景图片、文字等信息的位置确定好后,将背景图片的overflow-x设置为 hidden、overflow-y设置为 auto,最后定好层级z-index。
头像部分采用background-size: cover的方式将图片最大限度的填充其父元素。
正文部分
利用bootstrap的栅格系统做好布局,其后为正文添加三个标签页。
添加日记、游记、照片
日记的内容用组件编写即可。之后为日记部分添加过渡效果和模态框。
模态框用v-for、插值的方法编写。
利用vue的父子传值及组件的方法获取到日记的正文内容,并为其绑定v-if="on",on为true,之后为过渡按钮绑定click事件,通过改变on的布尔值来控制日记正文的过渡效果;
通过添加日记按钮来为日记部分添加内容。在添加日记按钮上绑定click事件(click事件的函数接收一个event参数,用以消除事件冒泡),通过鼠标点击来添加 / 移除模态框的class(若模态框隐藏,则为其添加类active、类show使其显示;若模态框已显示,再次点击按钮为模态框移除类active、类show让其隐藏。)来控制模态框的显示 / 隐藏。添加内容的界面用模态框来承载,模态框的内容同样用vue来处理。
模态框中的提交功能
1.模态框中的提交功能由一个button按钮承载,并为其绑定click事件:click事件所绑定的函数接收一个参数,用于if-else语句的条件判断:
- 当传入的参数是字符串dairy时,将item对象添加到dairy数组中,接着通过v-for、插值的方式将内容输出到正文中。
- 点击提交按钮的同时,模态框隐藏也被隐藏了。这是因为提交按钮的同时,模态框的属性inputClass的属性值改变成了 .fade和 .modal-dialog。
照片的动画
这里为照片页面添加的动画效果是:3秒内以慢速结束的方式改变x轴或y轴的位置。
这个动画的原理是:当点击按钮切换图片离开时,图片向y轴下方偏移500px,同时透明度降为0;图片进入时,图片向x轴右侧偏移500px,同时透明度增加到1。图片离开或进入所需要的时间为3s,且离动画结束时间越近,动画播放速度越慢。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>微博2.0</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootswatch/4.1.2/minty/bootstrap.min.css">
<link href="https://cdn.bootcss.com/animate.css/3.5.2/animate.min.css" rel="stylesheet">
<style>
#info-box {
background: url("https://static1.bcjiaoyu.com/39de4af0b42ec67bbb9f9003ff6fcfb6_q.jpeg-767x1499");
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 300px;
overflow-x: hidden;
overflow-y: auto;
z-index: 100;
}
#img-box {
background: url("https://resource.bcgame-face2face.haorenao.cn/992e48e80887364b93e334e133ffd4e1_d.jpg-634x952");
width: 200px;
height: 200px;
border-radius: 50%;
margin: 20px auto;
background-size: cover;
background-position: top center;
/* background-position: center; 只能调节图片在像框中的位置,而不能调节图片在 #img_background 中的位置。*/
}
#info-text {
font-size: 1.1em;
font-weight: bold;
color: rgb(5, 5, 5);
}
#content {
position: absolute;
top: 0px;
left: 300px;
bottom: 0;
right: 0;
overflow-y: auto;
overflow-x: hidden;
}
/*日记、游记——过渡*/
.slide-enter-active,.slide-leave-active{
transition:opacity 1s;
}
.slide-enter,.slide-leave-to{
opacity:0;
}
/*解决照片定位错乱*/
#photo .row div{
display: flex;
flex-wrap: wrap;
}
.row .card{
width:100%;
height: 300px;
}
/* 照片集--动画 */
.fade-enter-active,.fade-leave-active{
transition: all 3s ease-out;
}
.fade-enter{
transform: translateX(500px);
opacity: 0;
}
.fade-leave-active{
transform: translateY(500px);
opacity: 0;
}
</style>
</head>
<body>
<!--个人信息栏-->
<div id="info-box" class="text-center">
<h1>Nancy</h1>
<div id="img-box"></div>
<div id="info-text">
<p>一直都喜欢编程的Nancy</p>
<p>正在努力学编程的Nancy</p>
<p>会变得更厉害的Nancy</p>
</div>
<a href="https://www.weibo.com/"><img id="sina" src="./imges/微博1.png"></a>
</div>
<!--微博主页-->
<!--导航栏-->
<div id="content">
<ul class="nav nav-tabs">
<li class="nav-item"><a class="nav-link" href="#dairy-post-info" data-toggle="tab">日记</a></li>
<li class="nav-item"><a class="nav-link" href="#travel" data-toggle="tab">游记</a></li>
<li class="nav-item"><a class="nav-link" href="#photo" data-toggle="tab">照片集</a></li>
</ul>
<div class="tab-content">
<!--日记-->
<div class="tab-pane active show" id="dairy-post-info">
<!--添加过渡效果-->
<div v-for="(item,index) in dairy" class="jumbotron">
<transition-group name="slide" tag="div">
<text-content-component v-bind:item="item" v-bind:key="index" v-if="on"></text-content-component>
</transition-group>
</div>
<button class="btn btn-primary" v-on:click="on=!on">过渡</button>
<button class="btn btn-primary" v-on:click="showInput">添加日记</button>
<div v-bind:class="inputClass" role="document">
<div class="modal-content">
<div class="modal-body">
<div class="form-group row" v-for="(value,key) in item">
<label class="col-md-2 col-form-label">{{key}}</label>
<div class="col-md-10">
<input type="text" class="form-control is-valid" v-model:value="item[key]">
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" v-on:click="submit('dairy')">提交</button>
</div>
</div>
</div>
</div>
<!--游记-->
<div class="tab-pane container-fluid" id="travel">
<div class="jumbotron" v-for="item in travel">
<div class="row">
<div class="col-md-5">
<img height="300" width="400" v-bind:src="item.img">
</div>
<div class="col-md-7">
<transition name="custom" enter-active-class="animated tada" leave-active-class="animated bounceOutRight">
<div v-if="isshow">
<h2 name="post-title">
<span class="display-3 text-primary">{{item.date}}</span>
<br>
<span name="title">{{item.title}}</span>
</h2>
<p>{{item.ins}}</p>
<hr>
<p>{{item.content}}</p>
</div>
</transition>
</div>
</div>
</div>
<button class="btn btn-primary" @click="isshow=!isshow">动画</button>
<button class="btn btn-primary" v-on:click="showInput">添加游记</button>
<div v-bind:class="inputClass">
<div class="modal-content">
<div class="modal-body">
<div class="form-group row" v-for="(value,key) in item">
<label class="col-md-2 col-form-label">{{key}}</label>
<div class="col-md-10">
<input type="text" class="form-control is-valid" v-model:value="item[key]">
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" v-on:click="submit('travel')">提交</button>
</div>
</div>
</div>
</div>
<!--照片集-->
<div class="tab-pane container" id="photo">
<div class="row">
<transition-group name="fade" tag="div">
<pic-content-component v-for="(item,index) in pics" v-bind:item="item" v-bind:key="index" v-if="show"></pic-content-component>
</transition-group>
</div>
<button class="btn btn-primary" v-on:click="show=!show">动画</button>
<button class="btn btn-primary" v-on:click="showInput">添加照片</button>
<div v-bind:class="inputClass">
<div class="modal-content">
<div class="modal-body">
<div class="form-group row" v-for="(value,key) in item">
<label class="col-md-2 col-form-label">{{key}}</label>
<div class="col-md-10">
<input type="text" class="form-control" v-model="item[key]">
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" v-on:click="submit('pics')">提交</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
Vue.component("text-content-component",{
props:["item"],
template:`<div class="jumbotron">
<h2>
<span class="display-3 text-primary">{{item.date}}</span>
<span name="title">{{item.title}}</span>
</h2>
<p>{{item.ins}}</p>
<hr>
<p>{{item.content}}</p>
</div>`
})
Vue.component("pic-content-component",{
props:["item"],
template:`<div class="col-md-4">
<div class="card">
<img class="card-img" v-bind:src="item.img" height='300' alt="Card image">
<div class="card-img-overlay" style="color:azure">
<h4 class="card-title">{{item.title}}</h4>
<p class="card-text">{{item.content}}</p>
<p class="text-muted card-text">{{item.date}}</p>
</div>
</div>
</div>`
})
var contentApp = new Vue({
el: "#content",
methods: {
showInput: function (event) {
if (this.inputClass === 'fade modal-dialog') {
this.inputClass = 'fade modal-dialog active show'
} else {
this.inputClass = 'fade modal-dialog'
}
},
submit: function (message) {
if (message === "dairy") {
this.dairy.push(Object.assign({}, this.item))
} else if (message === "travel") {
this.travel.push(Object.assign({}, this.item))
} else {
this.pics.push(Object.assign({}, this.item))
}
this.inputClass = "fade modal-dialog"
}
},
data: {
on:true,
isshow:true,
show:true,
//fade与modal-dialog顺序不能颠倒。
inputClass: "fade modal-dialog",
dairy: [
{
date: "2018/07/30",
title: "学习Vue.js的第一天",
ins: "Inscription",
content: "很容易上手的Vue.js"
},
{
date: "2018/07/31",
title: "学习Vue.js的第二天",
ins: "lalala",
content: "好好学习 天天向上"
}
],
item: {
img: "填入图片地址。若是添加'日记',可忽略不填",
date: "填入日期",
title: "标题",
ins: "题记",
content: "内容"
},
travel: [
{
img: "https://cdn.pixabay.com/photo/2017/12/03/17/30/alley-2995354_1280.jpg",
date: "2018/07/30",
title: "Travel around world",
ins: "Inscription",
content: "Great time!"
},
{
img: "https://static1.bcjiaoyu.com/b3a608bf2b85a75ece602642f19b3f1e_d.jpg-1042x703",
date: "2018/07/31",
title: "Travel around world",
ins: "Inscription",
content: "What a great time!"
}
],
pics: [
{
img: "https://images.unsplash.com/photo-1532714845903-d7b2a053e92b?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=85fe6e18e27b3c748112641fd0bcfb12&auto=format&fit=crop&w=500&q=60",
title: "Pics story",
content: "This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.",
date: "update 2018/07/30"
},
{
img: "https://cdn.pixabay.com/photo/2018/05/11/23/45/highway-3392100__340.jpg",
title: "Pics story",
content: "This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.",
date: "update 2018/07/30"
},
{
img: "https://cdn.pixabay.com/photo/2018/05/30/16/23/fruit-3441830__340.jpg",
title: "Pics story",
content: "This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.",
date: "update 2018/07/30"
},
{
img: "https://cdn.pixabay.com/photo/2018/06/04/23/42/raspberry-3454504_1280.jpg",
title: "Pics story",
content: "This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.",
date: "update 2018/07/30"
},
{
img: "https://cdn.pixabay.com/photo/2018/07/14/22/53/currants-3538617_1280.jpg",
title: "Pics story",
content: "This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.",
date: "update 2018/07/30"
},
]
},
})
</script>
</body>
</html>