基于vue-cli实现一个全栈项目

2019-11-18  本文已影响0人  梦想家小洋

使用js实现一个全栈的项目:向我提问,以前使用html静态页面实现的(https://github.com/AprilJoy/bulma),这次使用vue实现前端代码,效果如下

image.png

创建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 文件夹下创建文件

  1. HomeComponent.vue
  2. CreateComponent.vue
  3. EditComponent.vue
  4. 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>

可以通过下列地址验证一下效果

  1. http://localhost:8080/create
  2. http://localhost:8080/posts
  3. http://localhost:8080/edit/21

创建导航栏

在 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正在运行

  1. Vue development server
  2. Node.js server
  3. 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>
上一篇下一篇

猜你喜欢

热点阅读