1. 首先將文件夾進(jìn)行分類
組件化
2. 分析
- 由上面的圖可以看出,我們先將功能進(jìn)行模塊化劃分,將公共部分提取出來,放到一個(gè)common的文件夾內(nèi),然后根據(jù)不同的頁面進(jìn)行創(chuàng)建不同的文件夾,詳細(xì)如上圖所示。
3. 源代碼展示
- index.html
<!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>
<link rel="stylesheet" href="style/main.css">
</head>
<body>
<div id="app">
<app-goods></app-goods>
</div>
<!-- vue的全局組件, 全局自定義指令, 全局過濾器必須在vue實(shí)例之前定義, 否則vue實(shí)例無法解決 -->
<script src="./lib/vue.js"></script>
<script src="./lib/axios.js"></script>
<!-- 公共組件 -->
<script src="./components/common/header.js"></script>
<script src="./components/common/footer.js"></script>
<script src="./components/common/list.js"></script>
<script src="./components/common/search.js"></script>
<!-- 頁面級別組件 -->
<script src="./components/goods/goods.js"></script>
<script src="./components/goods/add.js"></script>
<script src="./components/home/home.js"></script>
<script src="./components/login/login.js"></script>
<!-- 導(dǎo)入過濾器 -->
<script src="./filter/date.js"></script>
<!-- 導(dǎo)入自定義指令 -->
<script src="./directive/focus.js"></script>
<!-- 入口 -->
<script src="./main.js"></script>
</body>
</html>
- style/main.css
.wrapper {
width: 800px;
margin: 20px auto;
}
.operation {
margin-bottom: 10px;
text-align: center;
line-height: 20px;
font-size: 18px;
}
.operation input {
padding: 5px;
border: 1px solid deepskyblue;
}
.operation button {
border-radius: 3px;
background-color: deepskyblue;
}
.search {
text-align: left;
line-height: 20px;
font-size: 18px;
}
.search input {
padding: 5px;
border: 1px solid deeppink;
}
#tb{
width: 800px;
border-collapse: collapse;
margin: 20px auto;
}
#tb th{
background-color: #0094ff;
color:white;
font-size: 16px;
padding: 5px;
text-align: center;
border: 1px solid black;
}
#tb td{
padding: 5px;
text-align: center;
border: 1px solid black;
}
- ./components/common/header.js
/*
* @Author: Robyn
* @Date: 2017-11-12 19:27:25
* @Last Modified by: Robyn
* @Last Modified time: 2017-11-12 19:27:25
*/
Vue.component('app-header', {
template: `
<header>
<h1>{{ title }}</h1>
<p>{{ content }}</p>
</header>`,
props: ['title'],
data: function() {
return {
content: '這是頭部文件內(nèi)容'
};
}
});
- ./components/common/footer.js
/*
* @Author: Robyn
* @Date: 2017-11-12 19:28:12
* @Last Modified by: Robyn
* @Last Modified time: 2017-11-12 19:28:32
*/
Vue.component('app-footer', {
template: `
<footer>
<p>{{ content }}</p>
<address>{{ address }}</address>
</footer>`,
data: function() {
return {
content: '這里是尾部內(nèi)容',
address: '北京市'
};
}
});
- ./components/common/list.js
/*
* @Author: Robyn
* @Date: 2017-11-12 19:29:30
* @Last Modified by: Robyn
* @Last Modified time: 2017-11-12 19:29:30
*/
Vue.component('app-list', {
template: `
<table id="tb">
<tr>
<th>編號</th>
<th>名稱</th>
<th>創(chuàng)建時(shí)間</th>
<th>操作</th>
</tr>
<!-- 沒有數(shù)據(jù)才顯示, 有數(shù)據(jù)隱藏 -->
<tr v-if="list.length == 0">
<td colspan="4">列表無數(shù)據(jù)</td>
</tr>
<!-- 渲染商品列表 -->
<tr v-for="item in list" >
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.ctime | date }}</td>
<td>
<!-- @符號是v-on的簡寫方式 -->
<a href="#" @click="deleteBtn(item.id)">刪除</a>
</td>
</tr>
</table>`,
props: ['list'],
data: function() {
return {};
},
methods: {
// 子組件里面監(jiān)聽刪除按鈕的點(diǎn)擊事件, 但是不負(fù)責(zé)刪除操作,
// 而是當(dāng)收到點(diǎn)擊事件的時(shí)候, 告訴父親, 它要?dú)⒁坞S便
deleteBtn(id) {
this.$emit('del', id);
}
}
});
- ./components/common/search.js
/*
* @Author: Robyn
* @Date: 2017-11-12 19:30:12
* @Last Modified by: Robyn
* @Last Modified time: 2017-11-12 19:30:12
*/
Vue.component('app-search', {
template: `
<div class="search">
<input type="text" placeHolder="請輸入篩選內(nèi)容" v-model="searchKey">
</div>`,
data: function() {
return {
searchKey: ''
};
},
watch: {
// 當(dāng)這個(gè)值變量時(shí), 我通過自定義事件通知父, 同時(shí)把最新的值也給傳過去
searchKey() {
this.$emit('change', this.searchKey);
}
}
});
- ./components/goods/goods.js
/*
* @Author: Robyn
* @Date: 2017-11-14 20:10:34
* @Last Modified by: Robyn
* @Last Modified time: 2017-11-14 20:10:34
*/
Vue.component('app-goods', {
template: `
<article>
<app-header v-bind:title="'商品管理'"></app-header>
<app-add-goods v-on:add="addGoods"></app-add-goods>
<app-search v-on:change="search"></app-search>
<app-list v-bind:list="searchGoodsList" v-on:del="deleteGoods"></app-list>
<app-footer></app-footer>
</article>
`,
data: function() {
return {
goodsList: [],
searchKeyword: ''
};
},
methods: {
// 通過id刪除商品, 現(xiàn)在不光要?jiǎng)h除本地的數(shù)據(jù), 還要調(diào)用接口刪除服務(wù)器上的數(shù)據(jù)
deleteGoods(delId) {
axios.get(`http://vue.studyit.io/api/delproduct/${delId}`)
.then((resp) => {
// 當(dāng)服務(wù)器刪除成功后, 本地再刪除
this.goodsList = this.goodsList.filter(
goods => goods.id != delId
);
});
},
// 接收搜索子組件傳遞過來的新值
search(keyword) {
this.searchKeyword = keyword;
},
// 獲取商品列表
getGoods() {
axios.get('http://vue.studyit.io/api/getprodlist')
.then(
(resp) => {this.goodsList = resp.data.message}
);
},
// 添加商品, 接口請求成功后, 為了刷新頁面, 再手動(dòng)調(diào)用一下getGoods方法
addGoods(name) {
axios.post('http://vue.studyit.io/api/addproduct', `name=${name}`)
.then(
(resp) => {alert('添加成功'); this.getGoods()}
);
}
},
computed: {
// 搜索后的商品列表
searchGoodsList() {
return this.goodsList.filter(
goods => goods.name === this.searchKeyword || this.searchKeyword == ''
);
}
},
// 數(shù)據(jù)可以使用了, 那么就發(fā)送請求
created() {
this.getGoods();
}
});
- ./components/goods/add.js
/*
* @Author: Robyn
* @Date: 2017-11-14 20:12:37
* @Last Modified by: Robyn
* @Last Modified time: 2017-11-14 20:12:37
*/
Vue.component('app-add-goods', {
template: `
<div class="operation">
<input type="text" placeholder="請輸入名稱" v-model="name">
<button type="button" v-on:click="addGoods">添加數(shù)據(jù)</button>
</div>`,
data: function() {
return {
name: ''
};
},
methods: {
// 把值發(fā)送給父使用
addGoods() {
this.$emit('add', this.name);
}
}
});
- ./components/home/home.js
/*
* @Author: Robyn
* @Date: 2017-11-12 19:31:33
* @Last Modified by: Robyn
* @Last Modified time: 2017-11-12 19:31:33
*/
Vue.component('app-home', {
template: `
<article>
<app-header v-bind:title="'首頁'"></app-header>
<app-footer></app-footer>
</article>
`,
data: function() {
return {};
}
});
- ./components/login/login.js
/*
* @Author: Robyn
* @Date: 2017-11-12 19:32:08
* @Last Modified by: Robyn
* @Last Modified time: 2017-11-12 19:32:08
*/
Vue.component('app-login', {
// 每個(gè)組件的模版, 必須要使用一個(gè)根元素包裹起來
template: `
<article>
<app-header v-bind:title="'登陸'"></app-header>
<app-footer></app-footer>
</article>
`,
data: function() {
return {};
}
});
- ./filter/date.js
/*
* @Author: Robyn
* @Date: 2017-11-12 19:32:43
* @Last Modified by: Robyn
* @Last Modified time: 2017-11-12 19:32:43
*/
// 實(shí)現(xiàn)一個(gè)處理日期的過濾器
Vue.filter('date', function(time) {
var date = new Date(time);
return `${ date.getFullYear() }-${ date.getMonth() + 1 }-${ date.getDate() }`;
});
- ./directive/focus.js
/*
* @Author: Robyn
* @Date: 2017-11-12 19:33:19
* @Last Modified by: Robyn
* @Last Modified time: 2017-11-12 19:33:19
*/
// 實(shí)現(xiàn)一個(gè)全局自動(dòng)焦點(diǎn)指令
Vue.directive('focus', {
inserted(node) {
node.focus();
}
});
- ./main.js
/*
* @Author: Robyn
* @Date: 2017-11-12 19:33:49
* @Last Modified by: Robyn
* @Last Modified time: 2017-11-12 19:33:49
*/
new Vue({
el: '#app',
data: {}
});