之前进行了webpack的相关配置,现在我们lai 实现一下具体页面
重构了目录结构
-src
- assets
- images
- background-image.jpg
- done.svg
- round.svg
- styles
- footer.styl
- global.styl
- todo
- footer.jsx
- header.vue
- item.vue
- tabs.vue
- todo.vue
- app.vue // 模板文件
- index.js // 入口文件
-package.json
-webpack.config.js
代码实现
// footer.styl
#footer
margin 40px
text-align: center
color: #eee
font-size 15px
text-shadow 0 3px 0 2px #eee
// global.styl
html, body
margin 0
padding 0
width 100%
height 100%
body
background-image url(../images/background-image.jpg)
background-size cover
background-position center
font 14px 'microsoft yahei'
color #000000
font-weight 500
// index.js
import Vue from 'vue'
import App from './app.vue'
import './assets/styles/global.styl'
const root = document.createElement('div'); // 根节点
document.body.appendChild(root);
new Vue({
render: (h)=> h(App) // 将App渲染至根节点
}).$mount(root)
// app.vue
<template>
<div id="app">
<div class="cover">
<m-header></m-header>
<todo></todo>
<Footer></Footer>
</div>
</div>
</template>
<script>
import MHeader from './todo/header.vue'
import Footer from './todo/footer.jsx'
import Todo from './todo/todo.vue'
export default {
data() {
return {
test: "testsdsassadds"
};
},
components: {
MHeader,
Footer,
Todo
}
};
</script>
<style lang="stylus" scoped>
#app
position absolute
left 0
right 0
top 0
bottom 0
.cover
position absolute
left 0
right 0
top 0
bottom 0
background-color #555
opacity 0.5
z-index 1
</style>
// header.vue
<template>
<header class="main-header">
<h1>Meils - todo</h1>
</header>
</template>
<style lang="stylus" scoped>
.main-header
text-align: center
h1
font-size: 80px
color rgba(175, 47, 47, 1)
margin: 20px
</style>
// footer.jsx
import '../assets/styles/footer.styl'
export default{
data () {
return {
author: 'Meils',
blog: 'scopedSlots'
}
},
render() {
return (
<div id="footer">
<span>Power by {this.author},欢迎访问作者博客:{this.blog}</span>
</div>
)
}
}
// item.vue
<template>
<div :class="['todo-item', todo.completed ? 'completed' : '']">
<input type="checkbox"
class="toggle"
v-model="todo.completed"
>
<label class="label">{{todo.content}}</label>
<button class="destroy" @click="deleteTodo"></button>
</div>
</template>
<script>
export default {
props: {
todo : {
type: Object,
require: true
}
},
methods: {
deleteTodo () {
// this.$emit 触发del事件,并返回 todo.id
this.$emit('del', this.todo.id)
}
}
}
</script>
<style lang="stylus" scoped>
.todo-item{
position relative
background-color #fff
font-size 16px
border-bottom 1px solid rgba(0,0,0,0.06)
&:hover{
.destroy:after{
content: '×'
}
}
label{
white-space: pre-line;
word-break: break-all;
padding: 15px 60px 15px 15px;
margin-left: 45px;
display: block;
line-height: 1.2;
transition: color 0.4s;
}
&.completed{
label{
color: #d9d9d9;
text-decoration line-through
}
}
}
.toggle{
text-align: center;
width: 40px;
height: 40px;
line-height: 40px
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
border: none;
appearance: none;
outline none
padding-left 5px
cursor pointer
&:after{
content: url('../assets/images/round.svg')
}
&:checked:after{
content: url('../assets/images/done.svg')
}
}
.destroy{
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 30px;
color: #cc9a9a;
margin-bottom: 11px;
transition: color 0.2s ease-out;
background-color transparent
appearance none
border-width 0
cursor pointer
outline none
}
</style>
// tabs.vue
<template>
<div class="helper">
<span class="left">{{unFinishedTodoLength}} 项待办</span>
<span class="tabs">
<span
v-for="state in states"
:key="state"
:class="[state, filter === state ? 'actived' : '']"
@click="toggleFilter(state)"
>
{{state}}
</span>
</span>
<span class="clear" @click="clearAllCompleted()">
清空
</span>
</div>
</template>
<script>
export default {
// props 接收父组件传过来的值
props: {
filter: {
type: String,
required: true,
},
todos: {
type: Array,
required: true
}
},
data() {
return {
states: ['all', 'active', 'completed']
}
},
computed: {
unFinishedTodoLength() {
return this.todos.filter(todo => !todo.completed).length;
}
},
methods: {
toggleFilter(state) {
// 由父组件触发实现
this.$emit('toggle', state);
},
clearAllCompleted() {
this.$emit('clearAllCompleted');
}
}
}
</script>
<style lang="stylus" scoped>
.helper {
font-weight 100
display flex
justify-content space-between
padding 5px 0
line-height 30px
background-color #ffffff
font-size 14px
font-smoothing: antialiased;
}
.left, .clear, .tabs {
padding 0 10px
box-sizing border-box
}
.left, .clear {
width 150px
}
.left {
text-align left
}
.clear {
text-align: right
cursor pointer
}
.tabs {
width 200px
display flex
justify-content space-around
* {
display inline-block
padding 0 10px
cursor pointer
border 1px solid rgba(175, 47, 47, 0)
&.actived {
border-color rgba(175, 47, 47, 0.4)
border-radius 5px
}
}
}
</style>
// todo.vue
<template>
<section class="real-app">
<input type="text"
class="add-input"
autofocus="autofocus"
placeholder="接下来要做什么?"
@keyup.enter="addTodo($event)">
<items :todo="todo" v-for="todo in filteredTodos" :key="todo.id" @del="del"></items>
<tabs @clearAllCompleted="clearAllCompleted"
:filter="filters"
:todos="todos"
@toggle="toggleFilter"></tabs>
</section>
</template>
<script>
import Items from './item.vue'
import Tabs from './tabs.vue'
let id = 0;
export default {
data () {
return {
todos: [],
filters: 'all'
}
},
computed: {
filteredTodos() {
if (this.filters === 'all') {
return this.todos
}
const completed = this.filters === 'completed';
// 将todos数组中,completed为true的值过滤出来,并返回一个新数组
return this.todos.filter(todo => completed === todo.completed);
}
},
methods: {
addTodo (e) {
this.todos.unshift({
id: id++,
content: e.target.value.trim(),
completed: false
})
},
del (id) {
this.todos.splice(this.todos.findIndex(todo => todo.id === id), 1)
// findIndex方法接受一个函数,返回对应元素的索引值,
/* 获取数组中年龄大于 18 的第一个元素索引位置
var ages = [3, 10, 18, 20];
function checkAdult(age) {
return age >= 18;
}
function myFunction() {
document.getElementById("demo").innerHTML = ages.findIndex(checkAdult);
}
// 2
*/
},
toggleFilter(state) {
this.filters = state
},
clearAllCompleted() {
// 给todos赋一个新的值(即todo.completed为false的值)
this.todos = this.todos.filter(todo => todo.completed === false)
}
},
components: {
Items,
Tabs
}
}
</script>
<style lang="stylus" scoped>
.real-app
width: 700px
margin: 0px auto
box-shadow : 0 0 5px #666666
.add-input
position: relative
margin: 0
width: 100%
font-size: 20px
font-family: inherit
font-weight: inherit
line-height: 1.4em
border: 0
outline: none
color: inherit
box-sizing: border-box
font-smoothing: antialiased
padding: 16px 16px 16px 60px
border: none
box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03)
</style>
未完待续 ~~ 下一篇会是webpack的一些优化