Vue + Express实现一个表单提交

最近在折腾一个cms系统,用的vue+express,但是就一个表单提交就弄了好久,记录一下。

环境:
Node10+
前端:Vue
服务端:Express

依赖包:

  • vue
  • express
  • axios
  • express-formidable
  • element-ui(可选)
    前言:
    axios get 请求参数是: params
    axios post 请求参数是: data
    express get 接受参数 是 req.query
    express post 接受参数是:req.fields, 接受文件地址是:req.files.file.path

文件目录:
新建blog-cms文件。在blog-cms文件下新建client文件夹存放前端文件,在blog-cms文件下新建server存放后端文件。


161558680390_.pic.jpg

配置vue环境

在client文件下使用vue-cli工具,快速生成一个vue项目,
输入vue-cli安装命令:
npm install vue-cli -g
输入初始化命令(回车默认即可):
vue init webpack
启动:
npm start
然后打开浏览器http://localhost:8080/#/看到:

171558680667_.pic.jpg

表示安装成功

配置express环境

打开server文件夹,安装express,我们使用express 生成器,来快速生成一个express环境。
安装express-generator:
npm install express-generator -g
然后生成Express 应用:
express --view=ejs
之后下载依赖:
npm i
然后启动项目:
npm start
浏览器打开http://localhost:8080/#/看到:

181558680955_.pic.jpg

就说明安装成功了!

然后在server目录下新建models,在models下新建get_article_list.js文件写入:

 /* 目录:server/models/get_article_list.js */
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
    res.send('文章列表 响应成功!')
  });
 
  module.exports = router;

然后在server/app.js中添加代码:

var app=express();//这个一定要在上面
var getArticleList = require('./models/get_article_list')
app.use('/get_article_list', getArticleList)

然后我们重启服务,在浏览器打开:http://localhost:3000/get_article_list,显示如图,表示成功。

191558681652_.pic.jpg

axios

然后在client下,下载axios,用于ajax请求:
npm i axios --save
然后更改client/src/components/HelloWorld.vue:

<template>
  <div>
   <h1>{{this.msg}}</h1>
  </div>
</template>

<script>
import axios from "axios"
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: ''
    }
  },
  created() {
    axios.get('http://localhost:3000/get_article_list')
    .then(res=>{
      this.mas= res.data
    }).catch(err=>{
      console.log(err);
    })
  },
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
</style>

之后打开浏览器发现报错,

201558683480_.pic.jpg

这是因为跨域,我们使用cros解决。
直接在server/app.js添加:

var app = express()//在他的下面
// 以下 配置允许跨域请求; **********一定要放在上面**********
app.all('*', function (req, res, next) {
  res.header('Access-Control-Allow-Origin', '*')
  res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length, Authorization, Accept,X-Requested-With')
  res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS')
  res.header('X-Powered-By', ' 3.2.1')
  if(req.method=="OPTIONS") res.send(200);/*让options请求快速返回*/
  else  next();
})
// api
var getArticleList = require('./models/get_article_list')
app.use('/get_article_list', getArticleList)

然后重启服务器(在server下)执行npm start,然后再看了前端。就OK了,

211558684671_.pic.jpg

参考:不要再问我跨域的问题了

使用elementUI

elementUI官网
client下使用命令npm i element-ui --save下载
然后在main.js里使用:

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.config.productionTip = false
Vue.use(ElementUI);
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

get 前端

在 client/src/components下新建GetForm.vue:

<template>
    <div>
        <h2>get请求</h2>
        <el-form ref="form" :model="form" label-width="80px">
            <el-form-item label="文章标题">
                <el-input v-model="form.title"></el-input>
            </el-form-item>
            <el-form-item label="文章内容">
                <el-input type="textarea" v-model="form.content"></el-input>
            </el-form-item>
            <el-form-item>
                <el-button type="primary" @click="onSubmit">提交</el-button>
                <el-button>取消</el-button>
            </el-form-item>
        </el-form>
    </div>
</template>
<script>
import axios from 'axios'
export default {
    name: 'App',
    data () {
        return {
            form:{
                title: 'title',
                content: 'content'
            }
        }
    },
    methods: {
        onSubmit(){
            axios.get('http://127.0.0.1:3000/get_form',{
                params: this.form
            },{
                headers:{
                    'Content-Type': 'application/x-www-form-urlencoded'
                }
            }).then(res=>{
                console.log(res)
            }).catch(err=>{
                console.log(err)
            })
        }
}
}
</script>

然后在client/src/router/index.js下添加GetForm的路由:

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import GetForm from '@/components/GetForm.vue'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    {
      path:'/get_form',
      name: 'GetForm',
      component: GetForm
    }
  ]
})

然后更改client/src下的App.vue,添加一个GetForm跳转按钮:

<template>
  <div id="app">
    <div class="nav">
      <router-link to='/'>HelloWold</router-link>
      <router-link to='/get_form'>get form</router-link>
    </div>
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

之后打开http://localhost:8080/#/get_form看到

221558686564_.pic.jpg

表示成功。

get 后端

在server/models下新建get_form.js,输入:

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
    console.log(req.query)
  });
  
  module.exports = router;
  

在server/app.js新增get_from的接口:

// api
var getForm = require('./models/get_form.js')
app.use('/get_form', getForm)

然后重启后端服务器;
在前端中提交表单,就可以在后端的命令行工具上看到提交的信息了.


231558687197_.pic.jpg

post 前端

在client/src/components下添加PostForm.vue:

<template>
    <div>
        <h2>post请求</h2>
        <div>
           <form>
                <input type="text" value="" v-model="name" placeholder="请输入用户名">
                <input type="text" value="" v-model="age" placeholder="请输入年龄">
                <input type="file" @change="getFile($event)">
                <button @click="submitForm($event)">提交</button>
            </form>
        </div>
</div>
</template>
<script>
import axios from 'axios'
export default {
    name: 'PostForm',
    data () {
        return {
            age: '19',
            file: ''
        }
    },
    methods: {
          // post文件上传
        getFile(event){
            this.file = event.target.files[0];
            console.log(this.file);
        },
        submitForm(event){
             event.preventDefault();
            let formData = new FormData();
            formData.append('name', this.name);
            formData.append('age', this.age);
            formData.append('file', this.file);
            let config = {
              headers: {
                'Content-Type': 'multipart/form-data'
              }
            }
            axios.post('http://127.0.0.1:3000', formData, config)
            .then(res=>{
                console.log(res)
            }).catch(err=>{
                console.log(err)
            })
        }
}
}
</script>

同理,给PostForm添加路由和导航:
client/src/router/index.js里:

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import GetForm from '@/components/GetForm.vue'
import PostForm from '@/components/PostForm.vue'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    {
      path:'/get_form',
      name: 'GetForm',
      component: GetForm
    },
    {
      path: '/post_form',
      name: PostForm,
      component: PostForm
    }
  ]
})

APP.vue中;

<template>
  <div id="app">
    <div class="nav">
      <router-link to='/'>HelloWold</router-link>
      <router-link to='/get_form'>get form</router-link>
      <router-link to="/post_form">post form</router-link>
    </div>
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

post 后端

post 提交的表单里有图片文件,这里需要借助一个插件express-formidable
在sever下 使用命令npm install express-formidable --save
在server/models下新建post_form.js

var express = require('express');
var router = express.Router();
let formidableMiddleware = require('express-formidable');

router.use(formidableMiddleware({
    encoding: 'utf-8',
    uploadDir: 'public/images',//保存图片的目录
    multiples: true, // req.files to be arrays of files
    keepExtensions: true//保留后缀
  }))

/* POST home page. */
router.post('/', function(req, res, next) {
    console.log('图片地址:'+req.files.file.path);
    console.log(req.fields);
  });
  
module.exports = router;


照旧;在server/app.js里添加:

var postForm = require('./models/post_form.js')
app.use('/post_form', postForm)

然后重启服务器,然后去前端提交表单(包括图片)。
在后端显示这样表示成功了!


251558691887_.pic.jpg

下一章 :把提交的数据的插入到mongoDB数据库里

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容