成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

應(yīng)用vue2+vuex+vue-router+webpack2+es6+express+mysql技

voidking / 2400人閱讀

摘要:其實(shí)這里還是有漏洞的,坐等高手指出來(lái)微笑臉后臺(tái)沒(méi)有用生成一個(gè)完整的架構(gòu)。來(lái)自不同視圖的行為需要變更同一狀態(tài)。

最近對(duì)vue很感興趣,趁閑暇時(shí)間,模仿了wunderlist里面的部分功能,編寫(xiě)了前后端分離的基于vue技術(shù)棧和express的todolist小項(xiàng)目。寫(xiě)這篇博文來(lái)總結(jié)思考下。項(xiàng)目所在github,可以自行參考克隆。

本人博客

總體概覽

整個(gè)項(xiàng)目最終做成的樣子如下:

大家都看到了,整體實(shí)現(xiàn)的功能還是比較簡(jiǎn)單的。由于對(duì)express也很感興趣,就干脆自己動(dòng)手做了全棧。另外說(shuō)一下:這個(gè)項(xiàng)目只是自己摸索vue與express過(guò)程中,做出的成果,如果有哪個(gè)地方不對(duì)的,還請(qǐng)大神多多指教。

整個(gè)todolist界面分為左側(cè)的目錄分類(lèi)和右側(cè)的list。用戶(hù)切換不同的目錄可以對(duì)應(yīng)到相應(yīng)的list任務(wù)中,并且在該任務(wù)中能夠添加list和刪除list,也能夠標(biāo)記已完成與未完成。這些看上去都很簡(jiǎn)單,但是里面存在了挺多小細(xì)節(jié)的,我認(rèn)為,作為一個(gè)新手,尤其是對(duì)vue新,對(duì)express新又對(duì)他們很感興趣的新手,拿這個(gè)項(xiàng)目來(lái)練手個(gè)人覺(jué)得很合適。

不多說(shuō)廢話了,先來(lái)看看我的項(xiàng)目目錄與大致的介紹吧。

項(xiàng)目結(jié)構(gòu)
├── README.md                        //這里是readme說(shuō)明文檔
├── node_modules                     //一些依賴(lài)在這里
├── build                            
│   ├── build.js
│   └── dev.js
├── db                               //數(shù)據(jù)庫(kù)相關(guān)的東西放在這里                           
│   └── dbConfig.js                  //數(shù)據(jù)庫(kù)配置文件
├── dist                             //webpack編譯后的目標(biāo)文件夾
├── package.json                     //這個(gè)就不說(shuō)了,是個(gè)前端都懂
├── server                           //服務(wù)器端相關(guān)的文件都在這里           
│   └── app.js                       //server服務(wù),后臺(tái)服務(wù)入口文件
├── src                              //前端源文件都在這里
│   ├── App.vue                      //vue頂級(jí)組件,包含了vue-router
│   ├── components                   //各個(gè)子組件
│   │   ├── common                   //包含了頁(yè)面的公共模塊,比如header,footer等
│   │   ├── menu-item.vue            //左側(cè)菜單欄組件
│   │   ├── search.vue               //搜索框組件
│   │   └── todo-list.vue            //list組件
│   ├── config                       //一些前端配置的東西可以放在這里
│   ├── directives                   //vue的一些指令封裝可以放在這里
│   ├── filters                      //vue的一些過(guò)濾器可以放在這里
│   ├── images                       //放置圖片
│   │   ├── Shapes.jpg
│   │   ├── article.jpeg
│   │   └── avatar.png
│   ├── less                         //公共樣式less相關(guān)放在這里
│   │   ├── common.less
│   │   ├── fonts
│   │   ├── index.less
│   │   ├── lessfont
│   │   ├── mixin.less
│   │   ├── reset.less
│   │   └── variable.less
│   ├── main.js                      //前端入口文件
│   ├── pages                        //放置不同的頁(yè)面,本項(xiàng)目只有一個(gè)頁(yè)面,所以暫定只有一個(gè)
│   │   └── index.vue
│   ├── route.js                     //路由配置文件
│   └── store                        //vuex相關(guān)邏輯放在這里
│       ├── actions.js               //actions相關(guān)
│       ├── getters.js               //getter相關(guān)
│       ├── index.js                 //頂端vuex設(shè)置,入口文件
│       ├── modules                  //放置模塊
│       ├── mutations.js             //mutation相關(guān)
│       ├── plugins.js               //插件相關(guān)
│       └── state.js                 //state相關(guān)
├── webpack.config.base.js           //webpack基本配置
├── webpack.config.dev.js            //開(kāi)發(fā)環(huán)境配置
└── webpack.config.prod.js           //線上環(huán)境配置,但沒(méi)有測(cè)試過(guò)也沒(méi)有怎么研究,可以暫時(shí)忽略

下面來(lái)分前后端兩個(gè)模塊大致講解一下:

后端

首先要準(zhǔn)備mysql數(shù)據(jù)庫(kù)服務(wù),我用MYSQLWorkbench客戶(hù)端界面新建數(shù)據(jù)庫(kù),初始化庫(kù)表信息,當(dāng)然你也可以不用圖形界面,直接用命令行。在dbConfig.js中配置好數(shù)據(jù)庫(kù)設(shè)置

module.exports = {
    host     : "localhost",
    user     : "your user name default root",
    password : "your password",
    database : "taskiller"
}

本項(xiàng)目中,數(shù)據(jù)庫(kù)數(shù)據(jù)表的新建,并沒(méi)有寫(xiě)在server服務(wù)中,在實(shí)際的項(xiàng)目中應(yīng)該有個(gè)自動(dòng)化的腳本自動(dòng)創(chuàng)建你需要的數(shù)據(jù)表和需要的字段信息。因?yàn)槭钱?dāng)成練手項(xiàng)目做的,所以一切都從簡(jiǎn)了,把項(xiàng)目用到的數(shù)據(jù)庫(kù)和數(shù)據(jù)表都事先建立好了。我的數(shù)據(jù)庫(kù)名是taskiller,需要在這個(gè)數(shù)據(jù)庫(kù)中,建兩個(gè)表:todo_listmenu,todolist用來(lái)存儲(chǔ)list信息,menu用來(lái)存儲(chǔ)目錄信息。示例:
menu表

+----+--------+----------+
| id | name   | selected |
+----+--------+----------+
|  1 | sdd    |        0 |
+----+--------+----------+

todo_list表

+--------------+----+------+---------+
| text         | id | done | menu_id |
+--------------+----+------+---------+
| sdfs         | 46 |    0 |       1 |
| this is life | 47 |    0 |       4 |
+--------------+----+------+---------+

接下來(lái)就是后端服務(wù)文件app.js了,看代碼說(shuō)話吧:

const path = require("path")
const express = require("express")
const mysql = require("mysql");
const dbConfig = require("../db/dbConfig");
const bodyParser = require("body-parser")

const insertMenu = "INSERT INTO menu SET ?"
const getMenu = "SELECT * FROM menu WHERE id = ?"
const getAllMenu = "SELECT * FROM menu"
const getTodolist = "SELECT * FROM todo_list WHERE menu_id = ?"
const insertTodolist = "INSERT INTO todo_list SET ?"
const deleteTodo = "DELETE from todo_list WHERE id = ?"
const updateTodolist = "UPDATE todo_list SET done = ? WHERE id = ?"

let menus;  //所有menu列表緩存

const app = express();
app.use(bodyParser());

//連接數(shù)據(jù)庫(kù) 
let connection = mysql.createConnection(dbConfig);

app.all("*", function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By"," 3.2.1")
    res.header("Content-Type", "application/json;charset=utf-8");
    next();
});

//添加目錄
app.post("/menu/add", function (req, res, next) {
  let reqParam = req.body;
  connection.query(insertMenu, reqParam, function(error, results, fields) {
      if(error) throw error;
      console.log(results, fields)
  })
  res.sendStatus(200);
  next()
});

//得到所有目錄
app.get("/menu/get", function(req, res, next) {
    connection.query(getAllMenu, function(error, results, fields) {
        if(error) throw error;
        menus = results;
        res.json(results);
        next()
    })
})


//得到指定id的目錄
app.get("/menu/get/:id", function(req, res, next) {
    console.log("ID:", req.params.id);
   
    connection.query(getMenu, req.params.id, function(error, results, fields) {
        if(error) throw error;
        res.json(results);
    })
})

//根據(jù)目錄獲取todolist
app.get("/todolist/get/:id", function(req, res, next) {
    connection.query(getTodolist, req.params.id, function(error, results, fields) {
        if(error) return error;
        res.json(results);
    })
})

//添加todolist到數(shù)據(jù)庫(kù)中
app.post("/todolist/add", function(req, res, next) {
    //text,done, menu_id 
    let reqParam = {
        "text": req.body.data.text,
        "done": false,
        "menu_id": req.body.data.curMenu
    };
    var insertId;

    connection.query(insertTodolist, reqParam, function(error, results, fields) {
      if(error) throw error;

      insertId = results.insertId;
      reqParam.id = insertId;
      res.json(reqParam)
    })
    
})

//刪除todolist
app.post("/todolist/delete", function(req, res, next) {
    let reqParam = req.body.id

    connection.query(deleteTodo, reqParam, function(error, results, fields) {
      if(error) throw error;
      console.log(results, fields)
    })
    res.sendStatus(200);
})

//改變todolist狀態(tài)
app.post("/todolist/toggle", function(req, res, next) {
    let reqParam = req.body;
    console.log(reqParam)

    connection.query(updateTodolist, [!reqParam.done, reqParam.id], function(error, results, fields) {
        if(error) throw error;

        console.log(results)
        res.sendStatus(200);
    })
})

app.listen(3001, function() {
    console.log("listening on port 3001")
})


connection.connect(function(err) {
  if (err) {
    console.error("error connecting: " + err.stack);
    return;
  }

  console.log("connected as id " + connection.threadId);
});

很簡(jiǎn)單,所有的接口功能應(yīng)該都是一目了然。因?yàn)楣P者主要鍛煉的還是vue相關(guān)的,express只是有興趣略微帶過(guò),因此沒(méi)有考慮很復(fù)雜很完善的一些邏輯。有幾個(gè)注意事項(xiàng):

因?yàn)榍岸说牡刂范丝谑?000,后端server的端口又設(shè)定了3001,這就涉及到了跨域,因此我加了這段代碼,來(lái)解決跨域的問(wèn)題。

app.all("*", function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
  res.header("X-Powered-By"," 3.2.1")
  res.header("Content-Type", "application/json;charset=utf-8");
  next();
});

其實(shí)這里還是有漏洞的,坐等高手指出來(lái)(微笑臉)

后臺(tái)express沒(méi)有用express-generator生成一個(gè)完整的架構(gòu)。筆者之前嘗試過(guò)用這種一鍵生成的工具快速搭建后臺(tái)環(huán)境,但是這樣就都用現(xiàn)成的,好多東西概念就會(huì)非常模糊,不太好掌握一些技術(shù)細(xì)節(jié),也不會(huì)很透徹理解這樣寫(xiě)的架構(gòu)到底是為什么,為什么不采用其他架構(gòu)方式?所以,筆者決定自己純手寫(xiě)后臺(tái)的server,這個(gè)最初的版本是寫(xiě)的最簡(jiǎn)單的版本,等后期再深入研究express的時(shí)候,再把這個(gè)雛形向著可擴(kuò)展性和模塊化發(fā)展。不過(guò)已經(jīng)對(duì)express很熟的同學(xué)完全可以不照著我這個(gè)小白的寫(xiě)法寫(xiě)~

前端 webpack配置

前端剛開(kāi)始我遇到的門(mén)檻就是webpack一些配置,網(wǎng)上的教程真的是五花八門(mén),由于本人的目的是學(xué)習(xí)vue的,并不是搗鼓webpack,所以,在webpack配置方面并沒(méi)有花很多的時(shí)間研究,也是在網(wǎng)上找教程,慢慢摸索倒騰出來(lái)的。不過(guò)經(jīng)過(guò)這次倒騰我認(rèn)識(shí)到,我有必要研究下webpack的一些東西了。不然配置個(gè)東西,太痛苦,并且前端技術(shù)日新月異,網(wǎng)上的教程五花八門(mén),有老舊版本的,有新的版本的,很容易讓人摸不著頭腦,建議還是去官網(wǎng)學(xué)習(xí)比較好。后期我研究了再寫(xiě)博文總結(jié)下經(jīng)驗(yàn)。

這里先貼一下我的webpack配置,有些地方做了簡(jiǎn)要的注釋。

webpack.config.base.js

const webpack = require("webpack");
const path = require("path");
const fs = require("fs");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const autoprefixer = require("autoprefixer");


const PATHS = {
  src: path.resolve(__dirname, "./src"),
  dist: path.resolve(__dirname, "./dist")
}

module.exports = {
  entry: {
    app: "./src/main.js",           // 整個(gè)SPA的入口文件, 一切的文件依賴(lài)關(guān)系從它開(kāi)始
    vendors: ["vue", "vue-router"]  // 需要進(jìn)行多帶帶打包的文件
  },
  output: {
    path: PATHS.dist,
    filename: "js/[name].js",
    publicPath: "/dist/",           // 部署文件 相對(duì)于根路由
    chunkFilename: "js/[name].js"   // chunk文件輸出的文件名稱(chēng) 具體格式見(jiàn)webpack文檔, 注意區(qū)分 hash/chunkhash/contenthash 等內(nèi)容, 以及存在的潛在的坑
  },
  devtool: "#eval-source-map",      // 開(kāi)始source-map. 具體的不同配置信息見(jiàn)webpack文檔
  module: {
    rules: [{
        test: /.vue$/,
        loader: "vue-loader"
      },
      {
        test: /.js/,
        loader: "babel-loader",
        exclude: /node_modules/
      },
      {
        test: /.(png|jpe?g|gif|svg)(?.*)?$/,
        loader: "url-loader?limit=10240&name=images/[name].[ext]"
      },
      {
        test: /.less/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: [
            "css-loader",
            "less-loader"
          ]
        })
       },
       {
        test: /.css/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: [
            "css-loader"
          ]
        })
       },
       {
          test: /.(eot|svg|ttf|woff|woff2|png)w*/,
          loader: "file-loader"
        }
     ]
  },
  resolve: {
    alias: {
      "vue$": "vue/dist/vue.common.js",
      "components": path.join(__dirname, "src/components"),   // 定義文件路徑, 加速打包過(guò)程中webpack路徑查找過(guò)程
      "lib": path.join(__dirname, "src/lib"),
      "less": path.join(__dirname, "src/less"),
      "filters": path.join(__dirname, "src/filters"),
      "directives": path.join(__dirname, "src/directives"),
    },
    extensions: [".js", ".less", ".vue", "*", ".json"]        // 可以不加后綴, 直接使用 import xx from "xx" 的語(yǔ)法
  },
  plugins: [
    new HtmlWebpackPlugin({                                   // html模板輸出插件
      title: "task kill",
      template: `${PATHS.dist}/template/index.ejs`,
      inject: "body",
      filename: `${PATHS.dist}/pages/index.html`
    }),
    new ExtractTextPlugin({                                   // css抽離插件,多帶帶放到一個(gè)style文件當(dāng)中.
      filename: `css/style.css`,
      allChunks: true,
      disable: false
    }),
    // 將vue等框架/庫(kù)進(jìn)行多帶帶打包, 并輸入到vendors.js文件當(dāng)中
    // 這個(gè)地方commonChunkPlugin一共會(huì)輸出2個(gè)文件, 第二個(gè)文件是webpack的runtime文件
    // runtime文件用以定義一些webpack提供的全局函數(shù)及需要異步加載的chunk文件
    // 具體的內(nèi)容可以看我寫(xiě)的blog 
    // [webpack分包及異步加載套路](https://segmentfault.com/a/1190000007962830)
    // [webpack2異步加載套路](https://segmentfault.com/a/1190000008279471)
    new webpack.optimize.CommonsChunkPlugin({
      names: ["vendors", "manifest"]
    })
  ]
}

webpack.config.dev.js

const merge = require("webpack-merge");

module.exports = merge(require("./webpack.config.base"), {
  devServer: {
    proxy: {
      "/api": {
        target: "http://localhost:3001",
        changeOrigin: true,
        secure: false,
        pathRewrite: {
          "^/api": ""
        }
      }
    }
  }
})

webpack.config.prd.js就不貼了,這次我也沒(méi)有用上,大家有興趣可以直接去github里看。

邏輯設(shè)計(jì) vuex概要

在這里不得不感謝vuex,這個(gè)東西對(duì)開(kāi)發(fā)效率的提升真的很有幫助,vuex不熟悉的童鞋可以去官網(wǎng)查閱,建議既然學(xué)習(xí)了vue了,vuex必不可少,真的會(huì)節(jié)省你很多的開(kāi)發(fā)時(shí)間。這里我就做個(gè)簡(jiǎn)要的介紹:

vuex是一個(gè)專(zhuān)為vue開(kāi)發(fā)的狀態(tài)管理模式,它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測(cè)的方式變化。
這個(gè)狀態(tài)自管理應(yīng)用包含以下幾個(gè)部分:

state,驅(qū)動(dòng)應(yīng)用的數(shù)據(jù)源;

view,以聲明方式將state映射到視圖;

actions,響應(yīng)在view上的用戶(hù)輸入導(dǎo)致的狀態(tài)變化。

比如以下的單一數(shù)據(jù)流示意圖:

但是,有過(guò)組件編寫(xiě)經(jīng)驗(yàn)的童鞋應(yīng)該知道,當(dāng)我們的應(yīng)用遇到多個(gè)組件共享狀態(tài)時(shí),單向數(shù)據(jù)流的簡(jiǎn)潔性很容易被破壞:

多個(gè)視圖依賴(lài)于同一狀態(tài)。

來(lái)自不同視圖的行為需要變更同一狀態(tài)。

對(duì)于問(wèn)題一,傳參的方法對(duì)于多層嵌套的組件將會(huì)非常繁瑣,并且對(duì)于兄弟組件間的狀態(tài)傳遞無(wú)能為力。對(duì)于問(wèn)題二,我們經(jīng)常會(huì)采用父子組件直接引用或者通過(guò)事件來(lái)變更和同步狀態(tài)的多份拷貝。以上的這些模式非常脆弱,通常會(huì)導(dǎo)致無(wú)法維護(hù)的代碼。

因此,誕生了vuex,用來(lái)把組件的共享狀態(tài)抽取出來(lái),以一個(gè)全局單例模式管理。在這種模式下,組件樹(shù)構(gòu)成了一個(gè)巨大的“視圖”,不管在樹(shù)的哪個(gè)位置,任何組件都能獲取狀態(tài)或者觸發(fā)行為!

另外,通過(guò)定義和隔離狀態(tài)管理中的各種概念并強(qiáng)制遵守一定的規(guī)則,代碼也會(huì)變得更結(jié)構(gòu)化且易維護(hù)。

來(lái)看看這張經(jīng)典的圖例:

大致的就介紹到這里啦,需要更加深入的童鞋可以移步官網(wǎng)。下面針對(duì)本項(xiàng)目的邏輯,介紹下我設(shè)計(jì)的vuex。

state設(shè)計(jì)

由于目前實(shí)現(xiàn)的邏輯還是較為簡(jiǎn)單,因此,只有涉及了3個(gè)state:

export const state = {
    todos: [],     //當(dāng)前選中目錄curMenu對(duì)應(yīng)的todolist
    curMenu: {},   //選中的目錄
    menus: []      //所有目錄列表
}

目錄對(duì)應(yīng)的todo列表的切換,我采用的方式是:curMenu只要一有變動(dòng)就會(huì)向后端發(fā)送請(qǐng)求,后臺(tái)返回該目錄下對(duì)應(yīng)的所有todo列表,更新到todos。因此,這里只設(shè)計(jì)了一個(gè)todos狀態(tài)就行了。

mutations設(shè)計(jì)

mutation只能同步,無(wú)法異步,因此mutations.js只設(shè)計(jì)狀態(tài)的改變。此處根據(jù)交互有這幾處涉及到的狀態(tài)改變:

向todos中添加todo

在todos中刪除選中的todo

更新選中todo的完成狀態(tài)

設(shè)置當(dāng)前目錄對(duì)應(yīng)的todos數(shù)組

設(shè)置所有的目錄列表menus

設(shè)置當(dāng)前選中的目錄curMenu

對(duì)應(yīng)的js代碼如下:

export const mutations = {
    //添加todo
    addTodo(state, {todo}) {
        state.todos.push(todo)
    },
    //刪除todos
    deleteTodo(state, {todo}) {
        state.todos.splice(state.todos.indexOf(todo), 1);
    },
    //設(shè)置當(dāng)前的todos
    setTodo(state, {todos}) {
        state.todos = todos
    },
    //切換todo的完成狀態(tài)
    toggleTodo(state, {todo}) {
        todo.done = !todo.done;
    },

    //左側(cè)menu切換,設(shè)置當(dāng)前menu值
    setCurMenu(state, {menu}) {
        state.curMenu = menu;
    },
    //設(shè)置menu值,
    getMenu(state, {menus}) {
        state.menus = menus;
    }
}
acitions設(shè)計(jì)

由于需要后臺(tái)存儲(chǔ)一些todo列表的狀態(tài),需要將一些動(dòng)作的變動(dòng)告知后臺(tái),后臺(tái)更新相應(yīng)的數(shù)據(jù)庫(kù)信息,需要添加actions。

這里要注意:actions.js主要放置一些與后臺(tái)交互相關(guān)的操作,而mutations.js只用作狀態(tài)的改變。

仔細(xì)看看交互,會(huì)發(fā)現(xiàn)這里存在以下幾個(gè)動(dòng)作:

獲取所有的目錄,即獲得menus列表

切換menu時(shí),向后臺(tái)獲取對(duì)應(yīng)的todolist,并更新對(duì)應(yīng)todos列表

用戶(hù)添加list時(shí),向后臺(tái)發(fā)送請(qǐng)求存儲(chǔ)在數(shù)據(jù)庫(kù)中

用戶(hù)刪除list時(shí),向后臺(tái)發(fā)送請(qǐng)求將數(shù)據(jù)庫(kù)中該條記錄刪除

用戶(hù)改變todolist中的某個(gè)list的狀態(tài)時(shí),向后臺(tái)發(fā)送請(qǐng)求更新數(shù)據(jù)庫(kù)中該條記錄的done字段

import axios from "axios";

const host = "http://localhost:3001"

//獲取所有的menu
export const getMenus = ({commit}) => {
    axios.get(host + "/menu/get")
    .then((response) => {
        var data = response.data;
        var initMenu
        data.forEach(function(item) {
            if(item.selected) {
                initMenu = item
            }
        })
        commit("getMenu", {menus: data});       //提交mutation,初始化menus列表
        
        commit("setCurMenu", {menu: initMenu}); //提交mutation,初始化curMenu。

        axios.get(host + "/todolist/get/"+initMenu.id)
        .then((response) => {
            var data = response.data;
            commit("setTodo", {todos: data})     //根據(jù)初始化的curMenu獲取todolist,并提交mutation更新todos列表
        })
        .catch( error => {
            console.log(error)
        })
    })
    .catch( error => {
        console.log(error)
    })
}

//確切的講是getCurTodoList,得到當(dāng)前menu對(duì)應(yīng)的todolist
export const setCurMenu = ({commit}, menuData) => {
    axios.get(host + "/todolist/get/"+menuData.id)
    .then((response) => {
        var data = response.data;
        commit("setTodo", {todos: data})               //用數(shù)據(jù)庫(kù)返回的數(shù)據(jù)提交mutation,更新todo列表
        commit("setCurMenu", {menu: menuData.menu})    //更新當(dāng)前目錄,提交mutation來(lái)更新curMenu值
    })
    .catch( error => {
        console.log(error)
    })
}

//添加todo
export const addTodo = ({commit}, data) => {
    axios.post(host + "/todolist/add", {
        data: data,
    })
    .then((response) => {
        commit("addTodo", {todo: response.data})   // 提交mutation,向todos中添加數(shù)據(jù)庫(kù)返回的記錄
    })
    .catch( error => {
        console.log(error)
    })
}

//刪除todo
export const deleteTodo = ({commit}, todo) => {
    axios.post(host + "/todolist/delete", {
        id: todo.todo.id,
    })
    .then((response) => {
        commit("deleteTodo", todo)               //提交mutation,在todos中刪除該條記錄
    })
    .catch( error => {
        console.log(error)
    })
}

//完成與未完成的切換
export const toggleTodo = ({commit}, todo) => {
    axios.post(host + "/todolist/toggle", {
        id: todo.todo.id,
        done: todo.todo.done
    })
    .then((response) => {
        console.log(response)
        commit("toggleTodo", {todo: todo.todo})    //提交mutation,更新該條todo的完成狀態(tài)
    })
    .catch( error => {
        console.log(error)
    })
}
getters

細(xì)心的同學(xué)會(huì)發(fā)現(xiàn),我的界面里面分門(mén)別類(lèi)的顯示了已完成和未完成的類(lèi)別,因此需要通過(guò)getters來(lái)根據(jù)todos的數(shù)據(jù)獲得對(duì)應(yīng)的數(shù)據(jù)

export const doneTodos = state => {
    return state.todos.filter(item => item.done)
}

export const undoneTodos = state => {
    return state.todos.filter( item => !item.done)
}
組件 頁(yè)面組件

這里我就不多贅述了,都是組件相關(guān)的概念,要細(xì)講的話概念點(diǎn)就太多了,看不懂的建議大家去vue官網(wǎng)學(xué)習(xí)相關(guān)概念再來(lái)看。

index.vue





這里的mapStatemapGetters等都在vuex官網(wǎng)里面有介紹,前面的三點(diǎn)...es6的語(yǔ)法對(duì)象展開(kāi)符,不懂的童鞋可google一下,網(wǎng)上一堆教程。

我們可以看到,這個(gè)頁(yè)面我用到了menus組件和todo-list組件,這里我遇到過(guò)一個(gè)坑,vue文件的模板template中的元素只能有一個(gè)根節(jié)點(diǎn),不能有多個(gè)根節(jié)點(diǎn),大家寫(xiě)的時(shí)候在只在頂層寫(xiě)一個(gè)標(biāo)簽就好了。

menus組件

menus.vue



menu-item.vue



todo-list組件

todo-list.vue



總結(jié)

至此,主要的功能結(jié)構(gòu)都講的差不多了,有哪里講的不清楚的地方,還望指出來(lái),互相學(xué)習(xí)。
不得不說(shuō),vue框架用來(lái)來(lái)真的不錯(cuò),大家在開(kāi)發(fā)的時(shí)候,記?。阂獜臄?shù)據(jù)的角度思考問(wèn)題,一切就會(huì)變得如此簡(jiǎn)單。
這里記錄下接下來(lái)要添加的功能,如果有踩坑會(huì)繼續(xù)帶來(lái)博文分享互相交流學(xué)習(xí)下:

頂部路由添加user登錄信息

頂部多帶帶辟出一個(gè)路由顯示已完成任務(wù)或其他主題

左側(cè)menu欄目添加新建目錄功能,其實(shí)后端接口已經(jīng)寫(xiě)好,前端需要加一下

左側(cè)每個(gè)目錄需要有右鍵功能,右鍵彈出項(xiàng)目暫定: 重命名、刪除

右側(cè)添加任務(wù)的界面要改的好一點(diǎn),樣式細(xì)節(jié)需要調(diào)整

右側(cè)輸入框目前是點(diǎn)擊回車(chē)之后會(huì)自動(dòng)添加一個(gè)項(xiàng)目,但是在中文輸入法時(shí)直接按回車(chē)切換英文時(shí)存在bug,會(huì)導(dǎo)致list存在空白的情況,這個(gè)要處理一下

每個(gè)list是否需要可以編輯待定

左側(cè)目錄最右端顯示有幾條todolist功能添加

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/82759.html

相關(guān)文章

  • 無(wú)痛學(xué)會(huì)各種 2 的 Vue2+Vuex2+Webpack2 前后端同構(gòu)渲染

    摘要:它會(huì)檢測(cè)出最大靜態(tài)子樹(shù)就是不需要?jiǎng)討B(tài)性的子樹(shù)并且從渲染函數(shù)中萃取出來(lái)。這樣在每次重渲染的時(shí)候,它就會(huì)直接重用完全相同的同時(shí)跳過(guò)比對(duì)。需要注意的是,中的操作必須是同步的,不可以存在異步操作的情況。 新增:哈哈,最近又推出了 vue 的文章,在這里放個(gè)鏈接~手把手教你從零寫(xiě)一個(gè)簡(jiǎn)單的 VUE 感謝有人看我扯技術(shù),這篇文章主要介紹最近非?;鸬膙ue2前端框架的特點(diǎn)和vue2+vuex2+we...

    fish 評(píng)論0 收藏0
  • 無(wú)痛學(xué)會(huì)各種 2 的 Vue2+Vuex2+Webpack2 前后端同構(gòu)渲染

    摘要:它會(huì)檢測(cè)出最大靜態(tài)子樹(shù)就是不需要?jiǎng)討B(tài)性的子樹(shù)并且從渲染函數(shù)中萃取出來(lái)。這樣在每次重渲染的時(shí)候,它就會(huì)直接重用完全相同的同時(shí)跳過(guò)比對(duì)。需要注意的是,中的操作必須是同步的,不可以存在異步操作的情況。 新增:哈哈,最近又推出了 vue 的文章,在這里放個(gè)鏈接~手把手教你從零寫(xiě)一個(gè)簡(jiǎn)單的 VUE 感謝有人看我扯技術(shù),這篇文章主要介紹最近非?;鸬膙ue2前端框架的特點(diǎn)和vue2+vuex2+we...

    30e8336b8229 評(píng)論0 收藏0
  • 無(wú)痛學(xué)會(huì)各種 2 的 Vue2+Vuex2+Webpack2 前后端同構(gòu)渲染

    摘要:它會(huì)檢測(cè)出最大靜態(tài)子樹(shù)就是不需要?jiǎng)討B(tài)性的子樹(shù)并且從渲染函數(shù)中萃取出來(lái)。這樣在每次重渲染的時(shí)候,它就會(huì)直接重用完全相同的同時(shí)跳過(guò)比對(duì)。需要注意的是,中的操作必須是同步的,不可以存在異步操作的情況。 新增:哈哈,最近又推出了 vue 的文章,在這里放個(gè)鏈接~手把手教你從零寫(xiě)一個(gè)簡(jiǎn)單的 VUE 感謝有人看我扯技術(shù),這篇文章主要介紹最近非?;鸬膙ue2前端框架的特點(diǎn)和vue2+vuex2+we...

    Pluser 評(píng)論0 收藏0
  • 關(guān)于Vue2一些值得推薦的文章 -- 五、六月份

    摘要:五六月份推薦集合查看最新的請(qǐng)點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥(niǎo)雀呼晴,侵曉窺檐語(yǔ)。葉上初陽(yáng)乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門(mén),久作長(zhǎng)安旅。五月漁郎相憶否。小楫輕舟,夢(mèng)入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請(qǐng)::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...

    sutaking 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<