使用js实现一个全栈的项目:向我提问,以前使用html静态页面实现的(https://github.com/AprilJoy/bulma),这次使用vue实现前端代码,效果如下
创建vue cli 工程
vue create example
启动vue 的server
npm run serve
安装vue 依赖
npm install axios vue-router vue-axios --save
npm install bootstrap --save
在main.js 里引入bootstrap 4 的css文件
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import "bootstrap/dist/css/bootstrap.min.css";
Vue.config.productionTip = false;
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app");
创建 vue component
在src > components 文件夹下创建文件
- HomeComponent.vue
- CreateComponent.vue
- EditComponent.vue
- IndexComponent.vue
在 HomeComponent.vue 文件中添加如下代码
//Home
<template>
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card card-default">
<div class="card-header">Home Component</div>
<div class="card-body">I'm the Home Component component.</div>
</div>
</div>
</div>
</template>
<script>
export default {};
</script>
在 App.vue 中引入 HomeComponent.vue 文件
<template>
<div id="app">
<HomeComponent />
</div>
</template>
<script>
import HomeComponent from "./components/HomeComponent.vue";
export default {
name: "app",
components: {
HomeComponent
}
};
</script>
其他几个component文件类似
配置 vue-router
在router.js 文件中添加以下内容
import Vue from "vue";
import Router from "vue-router";
Vue.use(Router);
import HomeComponent from "./components/HomeComponent.vue";
import CreateComponent from "./components/CreateComponent.vue";
import IndexComponent from "./components/IndexComponent.vue";
import EditComponent from "./components/EditComponent.vue";
const routes = [
{
name: "home",
path: "/",
component: HomeComponent
},
{
name: "create",
path: "/create",
component: CreateComponent
},
{
name: "posts",
path: "/posts",
component: IndexComponent
},
{
name: "edit",
path: "/edit/:id",
component: EditComponent
}
];
export default new Router({
mode: "history",
routes: routes
});
在App.vue中添加 <router-view></router-view>,这样就回根据路由的地址渲染出对应的component
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "app",
components: {}
};
</script>
可以通过下列地址验证一下效果
创建导航栏
在 App.vue 中添加如下代码
// App.vue
<template>
<div class="container">
<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
<ul class="navbar-nav">
<li class="nav-item">
<router-link to="/" class="nav-link">Home</router-link>
</li>
<li class="nav-item">
<router-link to="/create" class="nav-link">Create Post</router-link>
</li>
<li class="nav-item">
<router-link to="/posts" class="nav-link">Posts</router-link>
</li>
</ul>
</nav>
<br />
<transition name="fade">
<router-view></router-view>
</transition>
</div>
</template>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s;
}
.fade-enter,
.fade-leave-active {
opacity: 0;
}
</style>
<script>
export default {
name: "app",
components: {}
};
</script>
创建想我提问的表单
// CreateComponent.vue
<template>
<div>
<h1>Create A Post</h1>
<form @submit.prevent="addPost">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Post Title:</label>
<input type="text" class="form-control" v-model="post.title">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Post Body:</label>
<textarea class="form-control" v-model="post.body" rows="5"></textarea>
</div>
</div>
</div><br />
<div class="form-group">
<button class="btn btn-primary">Create</button>
</div>
</form>
</div>
</template>
<script>
export default {
data(){
return {
post:{}
}
},
methods: {
addPost(){
console.log(this.post);
}
}
}
</script>
创建nodejs的后台server
安装插件
npm install nodemon --save-dev
body-parser:用于解析数据
core: 用于解决跨域的问题
nodemon:实时更新后台server代码,不用每次更改代码后刷新
在api目录下新建server.js文件
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const PORT = 4000;
const cors = require('cors');
app.use(cors());
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.listen(PORT, function(){
console.log('Server is running on Port:',PORT);
});
新建mongo数据库并连接
新建DB.js,存放数据库配置
module.exports = {
DB: "mongodb://localhost:8900/test"
}
server.js文件添加如下内容
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const PORT = 4000;
const cors = require("cors");
const mongoose = require("mongoose");
const config = require("./DB.js");
mongoose.Promise = global.Promise;
mongoose.connect(config.DB, { useNewUrlParser: true }).then(
() => {
console.log("Database is connected");
},
err => {
console.log("Can not connect to the database" + err);
}
);
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.listen(PORT, function() {
console.log("Server is running on Port:", PORT);
});
创建Mongoose的schema
在文件post.model.js file中新建如下内容,用于定义数据库中的数据结构。这部分定义的Post会在下面的路由文件中用到
// post.model.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
// Define collection and schema for Post
let Post = new Schema(
{
title: {
type: String
},
body: {
type: String
}
},
{
collection: "posts"
}
);
module.exports = mongoose.model("Post", Post);
定义node server 的路由
创建CRUD的操作代码在路由文件post.route.js中
const express = require("express");
let postRoutes = express.Router();
// Require Post model in our routes module
let Post = require("./post.model");
// Defined store route
postRoutes.post("/add", function(req, res) {
let post = new Post(req.body);
console.log(post);
post
.save()
.then(() => {
res.status(200).json({ business: "business in added successfully" });
})
.catch(() => {
res.status(400).send("unable to save to database");
});
});
// Defined get data(index or listing) route
postRoutes.route("/").get(function(req, res) {
console.log("erro");
Post.find(function(err, posts) {
if (err) {
res.json(err);
} else {
res.json(posts);
}
});
});
// Defined edit route
postRoutes.route("/edit/:id").get(function(req, res) {
let id = req.params.id;
Post.findById(id, function(err, post) {
if (err) {
res.json(err);
}
res.json(post);
});
});
// Defined update route
postRoutes.route("/update/:id").post(function(req, res) {
Post.findById(req.params.id, function(err, post) {
if (!post) res.status(404).send("data is not found");
else {
post.title = req.body.title;
post.body = req.body.body;
post
.save()
.then(() => {
res.json("Update complete");
})
.catch(() => {
res.status(400).send("unable to update the database");
});
}
});
});
// Defined delete | remove | destroy route
postRoutes.route("/delete/:id").delete(function(req, res) {
Post.findByIdAndRemove({ _id: req.params.id }, function(err) {
if (err) res.json(err);
else res.json("Successfully removed");
});
});
module.exports = postRoutes;
在文件server.js中添加
app.use("/posts", postRoute);
至此,server端内容搭建完毕,下面通过引入axios插件,实现前端向后端发起请求的功能
引入axios发送网络请求
import VueAxios from 'vue-axios';
import axios from 'axios';
Vue.use(VueAxios, axios);
现在一共有3个server正在运行
- Vue development server
- Node.js server
- MongoDB server
现在route.js文件的内容入下
import Vue from "vue";
import Router from "vue-router";
Vue.use(Router);
import VueAxios from "vue-axios";
import axios from "axios";
Vue.use(VueAxios, axios);
import HomeComponent from "./components/HomeComponent.vue";
import CreateComponent from "./components/CreateComponent.vue";
import IndexComponent from "./components/IndexComponent.vue";
import EditComponent from "./components/EditComponent.vue";
const routes = [
{
name: "home",
path: "/",
component: HomeComponent
},
{
name: "create",
path: "/create",
component: CreateComponent
},
{
name: "posts",
path: "/posts",
component: IndexComponent
},
{
name: "edit",
path: "/edit/:id",
component: EditComponent
}
];
export default new Router({
mode: "history",
routes: routes
});
实现后台数据在前端展示/删除的功能
在IndexComponent.vue文件中的代码如下
<template>
<div>
<h1>Posts</h1>
<div class="row">
<div class="col-md-10"></div>
<div class="col-md-2">
<router-link :to="{ name: 'create' }" class="btn btn-primary"
>Create Post</router-link
>
</div>
</div>
<br />
<table class="table table-hover">
<thead>
<tr>
<th>Title</th>
<th>Body</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="post in posts" :key="post._id">
<td>{{ post.title }}</td>
<td>{{ post.body }}</td>
<td class="btn-w">
<router-link
:to="{ name: 'edit', params: { id: post._id } }"
class="btn btn-primary"
>Edit</router-link
>
</td>
<td class="btn-w">
<button
class="btn btn-danger"
@click.prevent="deletePost(post._id)"
>
Delete
</button>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
data() {
return {
posts: []
};
},
created() {
let uri = "http://localhost:4000/posts";
this.axios.get(uri).then(response => {
this.posts = response.data;
});
},
methods: {
deletePost(id) {
let uri = `http://localhost:4000/posts/delete/${id}`;
/* eslint-disable */
this.axios.delete(uri).then(response => {
this.posts.splice(this.posts.indexOf(id), 1);
});
}
}
};
</script>
<style scoped>
td {
width: 50%;
}
</style>