關于全棧項目【臻美短視頻】總結

登錄注冊頁




























視頻展示頁


























上傳拍攝視頻頁

































以上是臻美短視頻的基本頁面。

這個項目的有幾大難點:
一、登錄注冊功能的實現(xiàn)
二、視頻數(shù)據(jù)的實時獲取以及上滑切換視頻
三、上傳視頻以及錄制視頻

那么我們一步一步分析
一、登錄注冊功能的實現(xiàn)

這里后臺使用的是nodejs,調用相應的端口就可以存入數(shù)據(jù)庫。

 








var express = require('express')
var multer = require('multer')
var jwt = require('jsonwebtoken');
var mysql = require('mysql');
var bodyParser = require('body-parser')
// 如果使用POST方法,就必須導入bodyParser,body-parser請求體解析模塊,是express的中間件用于接受請求體中的數(shù)據(jù),并解析為對象,解析之后的對象會將作為body屬性添加給rep對象
var fs = require('fs');
var join = require('path').join;
var web = express();
var secretkey = 'secretkey';
var connection = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: '',
    port: '3306',
    database: 'sv'
});
connection.connect();
web.use(express.static('public'))
// 設置服務器靜態(tài)文件夾,里面的文件都是呈現(xiàn)給人們看的網(wǎng)頁
web.use(bodyParser.json());
web.use(bodyParser.urlencoded({
    extended: true
}));

web.all("*", function (req, res, next) {
    res.header('Access-Control-Allow-Origin', req.headers.origin || '*');
    res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length, Authorization,\'Origin\',Accept,X-Requested-With');
    res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
    res.header('Access-Control-Allow-Credentials', true);
    res.header('X-Powered-By', ' 3.2.1');
    res.header('Content-Type', 'application/json;charset=utf-8');
            if (req.method.toLowerCase() == 'options')
                res.send(200); //讓options嘗試請求快速結束
            else
                next();
        })
//用戶登錄
web.post('/user/login', (req, res) => {
    var name = req.body.username;
    var passwd = req.body.password;
    var userStr = `select username,password,token from user where username="${name}" and password="${passwd}"`;
    connection.query(userStr, function (err, result) {
        if (err) {
            throw err;
        } else {
            res.json({
                message: result,
            })
        }
    })
})
//符合
web.post('/user/accord', (req, res) => {
    var token2 = req.body.token1;
    var userStr = `select username,token from user where token="${token2}"`;
    connection.query(userStr, function (err, result) {
        if (err) {
            throw err;
        } else {
            res.json({
                message: result,
            })
        }
    })
})
//用戶注冊
web.post('/user/register', (req, res) => {
    var name = req.body.username;
    var passwd = req.body.password;
    var token1 = jwt.sign({
        username: name
    }, secretkey, {
        expiresIn: 60 * 8
    });
    var json = {};
    var userStr = `select * from user where username="${name}"`;
    connection.query(userStr, function (err, result) {
        if (err) throw err;
        if (result.length > 0) {
            json.message = '用戶已經(jīng)存在';
            json.resultCode = 1;
        } else {
            json.message = '注冊成功';
            json.token = token1;
            json.resultCode = 200;
            var insertStr = `insert into user (username, password,token) values ("${name}", "${passwd}","${token1}")`;
            console.log(insertStr)
            connection.query(insertStr, function (err, res) {
                if (err) throw err;
            })
        }
        res.send(JSON.stringify(json))
    })
})
var fullName = '';
var pa="";
var y1="";
var i=0;
var userq=''
web.post('/username', function (req, res) {
    // res.send('')
    userq = req.body.name;
    console.log(userq)
})
var headerConfig = multer.diskStorage({
    // destination目的地
    destination: 'public/video',
    filename: function (req, file, cb) {
        var fileFormat = (file.originalname).split(".");
        cb(null, userq + '-' + Date.now() + "." + fileFormat[fileFormat.length - 1]);
    }
})
var upload = multer({
    storage: headerConfig
})
 function getJsonFiles(jsonPath) {
     let jsonFiles = [];
     function findJsonFile(path) {
         let files = fs.readdirSync(path);
         files.forEach(function (item, index) {
             let fPath = join(path, item);
             let stat = fs.statSync(fPath);
             if (stat.isDirectory() === true) {
                 findJsonFile(fPath);
             }
             if (stat.isFile() === true) {
                 let fail = fPath.slice(7);
                 jsonFiles.push('https://www.xxx.cn/xxx/' + fail);
             }
         });
     }
     findJsonFile(jsonPath);
    //  console.log(jsonFiles);
     pa = jsonFiles;
 }
web.post('/upload',upload.single('video'), function (req, res) {
    // res.send('')
    console.log('上傳成功')
})

web.get('/video', function (req, res) {
    getJsonFiles("./public/video");
    res.send(pa);
})
web.listen('7500', function () {
    console.log('服務器開啟')
})

 

前臺使用的是Vue,UI框架Vant。前臺比較簡單,這里不多過敘述。

<template>
  <div>
    <div class="logo"><img src="../assets/video.png" alt=""></div>
    <van-cell-group class="int">
      <van-field
        v-model="username"
        clearable
        label="用戶名"
        placeholder="請輸入用戶名"
        maxlength="6"
        clickable
      />
      <van-field
        v-model="password"
        type="password"
        label="密碼"
        maxlength="6"
        placeholder="請輸入密碼"
        clickable
      />
    </van-cell-group>
    <div class="foot">
      <van-button type="primary" color="#00CED1" class="login" @click="log" >登錄</van-button>
      <p class="reg" @click="reg">注冊</p>
    </div>
  </div>
</template>

<script>import md5 from 'js-md5'
const delay = (function () {
  let timer = 0
  return function (callback, ms) {
    clearTimeout(timer)
    timer = setTimeout(callback, ms)
  }
})()
export default {
  name: 'login',
  data () {
    return {
      username: '',
      password: '',
      sse: ''
    }
  },
  methods: {
    reg () {
      if (this.username.length !== 0 && this.password.length !== 0) {
        delay(() => {
          let postData = {
            username: this.username,
            password: md5(this.password)
          }
          this.$axios.post('https://xxx/xxxx/user/register', postData)
            .then((response) => {
              // success
              console.log(response.data)
              if (response.data.resultCode === 200) {
                this.$notify({
                  message: response.data.message,
                  duration: 1000,
                  background: '#07C160'
                })
                this.username = ''
                this.password = ''
              } else if (response.data.resultCode === 1) {
                this.$notify({
                  message: response.data.message,
                  duration: 1000,
                  background: '#FFA500'
                })
              }
            })
            .catch((error) => {
              // error
              console.log(error)
            })
        }, 500)
      } else {
        this.$notify({
          message: '注冊失敗!',
          duration: 1000,
          background: '#FF0000'
        })
      }
    },
    log () {
      delay(() => {
        let postData = {
          username: this.username,
          password: md5(this.password)
        }
        this.$axios.post('https://xxx/xxx/user/login', postData)
          .then((response) => {
            // success
            console.log(response.data.message)
            if (response.data.message.length === 0) {
              // ('登錄失敗')
              this.$notify({
                message: '登錄失敗!',
                duration: 1000,
                background: '#FF0000'
              })
            } else {
              localStorage.setItem('svuser', response.data.message[0].token)
              localStorage.setItem('svdata', JSON.stringify(response.data.message[0]))
              this.$router.push({
                name: 'index'
              })
              this.$notify({
                message: '登錄成功!',
                duration: 1000,
                background: '#07C160'
              })
            }
          })
          .catch((error) => {
            // error
            console.log(error)
          })
      }, 500)
    }
  }
}
</script>

 






二、視頻數(shù)據(jù)的實時獲取以及上滑切換視頻

視頻獲取直接調用接口就可以了

<template>
  <div class="index">
    <div class="close" @click="close">
      <div>
        <van-icon name="cross" color="#00CED1"/>
      </div>
    </div>
    <van-swipe style="height: 100vh;" vertical :show-indicators="false" @change="onChange"  touchable>
      <van-swipe-item v-for="(item,index) in list" :key="index">
        <div class="main" v-if="playIndex==index">
          <video  loop  :src="item"  preload  autoplay="autoplay" controls="controls"></video>
          <div class="foot">
            <p class="name">@ {{ item | capitalize }}</p>
          </div>
        </div>
      </van-swipe-item>
    </van-swipe>
    <div class="add">
      <div @click="b1()">
        <van-button icon="plus" color="#00CED1" />
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'index',
  data () {
    return {
      current: 0,
      list: '',
      playIndex: 0
    }
  },
  methods: {
    close () {
      this.$notify({
        message: '退出成功!',
        duration: 1000,
        background: '#07C160'
      })
      setTimeout(() => {
        localStorage.clear()
        window.location.reload()
      }, 1000)
    },
    onChange (index) {
      this.current = index
      this.playIndex = index
      console.log(index)
    },
    b1 () {
      const data1 = JSON.parse(localStorage.getItem('svdata'))
      this.$router.push({
        name: 'upload',
        params: {
          name: data1.username
        }
      })
    }
  },
  filters: {
    capitalize: function (value) {
      // console.log(value.slice(39))
      let a = value.slice(39)
      return a.split('-')[0]
    }
  },
  mounted () {
    // location.reload()
    // document.querySelector('video').playbackRate = 0.75
    const data1 = JSON.parse(localStorage.getItem('svdata'))
    if (data1.token === localStorage.getItem('svuser')) {
      // this.name = data1.username
      this.$axios.get('https://xxx/xxx/video/')
        .then((response) => {
          // success
          console.log(response.data)
          this.list = response.data
        })
        .catch((error) => {
          // error
          console.log(error)
        })
    }
  }
}
</script>

 

三、上傳視頻以及錄制視頻

這里使用的是node的multer模塊

var fullName = '';
var pa="";
var y1="";
var i=0;
var userq=''
web.post('/username', function (req, res) {
    // res.send('')
    userq = req.body.name;
    console.log(userq)
})
// 思路
// 上傳內容并儲存——1.設置存儲的地方——2.設置存儲時的名字{1.獲取原來名字的后綴,2.再重新命名}
var headerConfig = multer.diskStorage({
    // destination目的地
    destination: 'public/video',
    // fliename 文件名 后面跟函數(shù),函數(shù)有三個參數(shù)
    // file為當前上傳的文件
    filename: function (req, file, cb) {
        var fileFormat = (file.originalname).split(".");
        cb(null, userq + '-' + Date.now() + "." + fileFormat[fileFormat.length - 1]);
    }
})
// 設置使用當前的配置信息
// 上傳完照片后要使用的配置信息
var upload = multer({
    storage: headerConfig
})
 function getJsonFiles(jsonPath) {
     let jsonFiles = [];
     function findJsonFile(path) {
         let files = fs.readdirSync(path);
         files.forEach(function (item, index) {
             let fPath = join(path, item);
             let stat = fs.statSync(fPath);
             if (stat.isDirectory() === true) {
                 findJsonFile(fPath);
             }
             if (stat.isFile() === true) {
                 let fail = fPath.slice(7);
                 jsonFiles.push('https://xxx/xxx/' + fail);
             }
         });
     }
     findJsonFile(jsonPath);
    //  console.log(jsonFiles);
     pa = jsonFiles;
 }
// single 上傳單個文件; photo 為前端上傳文件的input標簽的name值
// upload.single('video')每次上傳單個文件的配置信息
web.post('/upload',upload.single('video'), function (req, res) {
    // res.send('')
    console.log('上傳成功')
})

web.get('/video', function (req, res) {
    getJsonFiles("./public/video");
    res.send(pa);
})

 

這里前臺直接使用的是Vant框架中的文件上傳組件,但是你需要注意的是需要將
let data = new FormData()
data.append('video', file.file)
然后再傳到后臺去

<template>
    <div class="upload">
      <div class="back" @click="onClickLeft">
        <van-icon name="arrow-left" color="#00CED1" size="26" />
      </div>
      <div class="box">
        <van-uploader  :after-read="afterRead" :max-count="1"  :max-size="10485760"    v-model="fileList" accept="video/*" @oversize='chance()' />
        <p>請上傳不大于10M視頻</p>
      </div>
    </div>
</template>
<script>
export default {
  name: 'upload',
  data () {
    return {
      fileList: [],
      e: 'video'
    }
  },
  methods: {
    chance () {
      this.$notify({
        message: '文件大小過大,請上傳小于10M視頻',
        duration: 1000,
        background: '#FFA500'
      })
    },
    onClickLeft () {
      history.back()
    },
    afterRead (file) {
      // console.log(file.content)// base64
      // function dataURItoBlob (base64Data) {
      //   var byteString
      //   if (base64Data.split(',')[0].indexOf('base64') >= 0) byteString = atob(base64Data.split(',')[1])
      //   else byteString = unescape(base64Data.split(',')[1])
      //   var mimeString = base64Data.split(',')[0].split(':')[1].split(';')[0]
      //   var ia = new Uint8Array(byteString.length)
      //   for (var i = 0; i < byteString.length; i++) {
      //     ia[i] = byteString.charCodeAt(i)
      //   }
      //   return new Blob([ia], {
      //     type: mimeString
      //   })
      // }
      // console.log(dataURItoBlob(file.content))
      let data = new FormData()
      data.append('video', file.file)
      // 此時可以自行將文件上傳至服務器
      this.$axios({
        url: 'https://xxx/xxx/upload/',
        method: 'POST',
        headers: {
          'Content-Type': 'multipart/form-data'
        },
        data: data
      }).then((response) => {
        // success
      })
        .catch((error) => {
          // error
          console.log(error)
        })
      // console.log(file)
      this.$notify({
        message: '發(fā)布成功',
        duration: 1000,
        background: '#07C160'
      })
    }
  },
  mounted () {
    this.$axios({
      url: 'https://xxx/xxx/username/',
      method: 'POST',
      data: {
        name: this.$route.params.name
      }
    }).then((response) => {
      // success
      console.log(response)
    })
      .catch((error) => {
        // error
        console.log(error)
      })
  }
}
</script>

 

作者:Vam的金豆之路

主要領域:前端開發(fā)

我的微信:maomin9761

微信公眾號:前端歷劫之路