基于vue-cli實現(xiàn)一個全棧項目

使用js實現(xiàn)一個全棧的項目:向我提問,以前使用html靜態(tài)頁面實現(xiàn)的(https://github.com/AprilJoy/bulma),這次使用vue實現(xiàn)前端代碼,效果如下

image.png

創(chuàng)建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");

創(chuàng)建 vue component

在src > components 文件夾下創(chuàng)建文件

  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>,這樣就回根據(jù)路由的地址渲染出對應的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

創(chuàng)建導航欄

在 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>

創(chuàng)建想我提問的表單

// 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>

創(chuàng)建nodejs的后臺server

安裝插件

npm install nodemon --save-dev

body-parser:用于解析數(shù)據(jù)
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數(shù)據(jù)庫并連接

新建DB.js,存放數(shù)據(jù)庫配置

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);
});

創(chuàng)建Mongoose的schema

在文件post.model.js file中新建如下內容,用于定義數(shù)據(jù)庫中的數(shù)據(jù)結構。這部分定義的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 的路由

創(chuàng)建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插件,實現(xiàn)前端向后端發(fā)起請求的功能

引入axios發(fā)送網(wǎng)絡請求

import VueAxios from 'vue-axios';
import axios from 'axios';

Vue.use(VueAxios, axios);

現(xiàn)在一共有3個server正在運行

  1. Vue development server
  2. Node.js server
  3. MongoDB server

現(xiàn)在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
});

實現(xiàn)后臺數(shù)據(jù)在前端展示/刪除的功能

在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>
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 開發(fā)一個項目,采用什么語言都可以,主要能熟練高效的開發(fā)都是合理的,這次我們采用vue來開發(fā)一個團隊項目。在開...
    MsgSS閱讀 3,055評論 3 9
  • 一、 組件component 1. 什么是組件? 組件(Component)是 Vue.js 最強大的功能之一。組...
    饑人谷_Leonardo閱讀 2,150評論 0 18
  • Vue.js起步 文檔 Vue.js是一個MVVM的前端框架,與React.js相似,都注重解決view層開發(fā)痛點...
    劉昊2018閱讀 315評論 0 0
  • 配置前說明:確保已安裝node環(huán)境。 檢查是否安裝node環(huán)境: 一、配置前命令簡寫說明: 1、npm i 和np...
    u5f20u5929u8000閱讀 1,567評論 3 7
  • 基于Vue的一些資料 內容 UI組件 開發(fā)框架 實用庫 服務端 輔助工具 應用實例 Demo示例 element★...
    嘗了又嘗閱讀 1,277評論 0 1

友情鏈接更多精彩內容