• blog之前端篇


    1. 初始化项目

    ① vue init webpack blog //然后一直回车,或者不用e2e, test, unit

    ② 修改package.json

    1 "scripts": {
    2     "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    3     "start": "node app.js",
    4     "unit": "jest --config test/unit/jest.conf.js --coverage",
    5     "e2e": "node test/e2e/runner.js",
    6     "test": "npm run unit && npm run e2e",
    7     "lint": "eslint --ext .js,.vue src test/unit test/e2e/specs",
    8     "build": "node build/build.js"
    9   }

    安装express框架,在根目录下创建app.js,和用express4.0创建的模板差不多,关键在于以下代码

    app.use("/*", express.static(path.join(__dirname, "dist")));

    这样开启服务后就可以访问打包后的dist文件夹下面的index.html

    ③ 添加global文件夹全局配置

    修改config/index 文件下的开发端口,改成可全局配置

    port: config.devHotPort, //默认为监听8080

    2. 获取36氪资讯

     由于是服务端渲染的,采用以往的http+cheerio模块是获取不到动态生成的网页的,所以需要安装cnpm install phantom --save;然后再用cheerio格式化;

    具体的教程可以看npm官网的首个例子,或者我GitHub上的代码;

     1 getSight(req, res) {
     2     let url = "http://36kr.com/", content, instance, page, status;
     3     let message = [];
     4 
     5     //文件格式{sightList : [], expire: ''}
     6     return file.readFile('files/mySelf/sightCache.json').then( result => {
     7         //缓存两个小时
     8         if(result.expire && (Date.now() - result.expire) < 7200000){
     9             message = result.sightList;
    10             return{
    11                 data: message,
    12                 str: "获取每日资讯列表"
    13             }
    14         }else{
    15             return phantom.create().then( result => {
    16                 instance = result;
    17                 return result.createPage()
    18             }).then( result => {
    19                 page = result;
    20                 return page.open(url)
    21             }).then( result => {
    22                 if(result = "success"){
    23                     return page.property('content');
    24                 }else{
    25                     this.paramError('url');
    26                 }
    27             }).then( result => {
    28                 content = result;
    29                 return instance.exit();
    30             }).then( result => {
    31                 let $ = cheerio.load(content, {decodeEntities: false});
    32                 $("li.real_time_wrapper").each(function(){
    33                     //console.log($(this).find('span.title').text())
    34                     message.push({
    35                         title : $(this).find('span.title').text(),
    36                         brief : $(this).find('div.show-content').text()
    37                     })
    38                 });
    39                 let tempStr = {
    40                     sightList :  message,
    41                     expire       :  Date.now()
    42                 };
    43                 return file.writeFile('files/mySelf/sightCache.json', JSON.stringify(tempStr))
    44 
    45             }).then( result => {
    46                 return{
    47                     data: message,
    48                     str: "获取每日资讯列表"
    49                 }
    50             })
    51         }
    52     })
    53 }
     1 static readFile(path){
     2     return new Promise( (resolve, reject) => {
     3         if(!fs.existsSync(path)){
     4             //fs.writeFileSync(path,'')没必要,且创建后,很奇怪发现上面17行return不了
     5             return resolve({})
     6         }
     7         let readstream = fs.createReadStream(path);
     8         let bufArr = [];
     9         let bufLen = 0, buf;
    10         return readstream.on('data', chunk => {
    11             bufArr.push(chunk);
    12             bufLen += chunk.length;
    13         }).on('end', () => {
    14             try{
    15                 buf = Buffer.alloc(bufLen);
    16                 for(let i = 0, pos = 0; i<bufArr.length&&pos<bufLen; i++){
    17                     bufArr[i].copy(buf,pos);
    18                     pos += bufArr[i].length;
    19                 }
    20                 let result = buf.toString();
    21                 if(result.length > 0 && result.indexOf('{') > -1){
    22                     return resolve(JSON.parse(result))
    23                 }else{
    24                     return resolve(result)
    25                 }
    26             }catch( e ){
    27                 log.error( e.message, "readFile" );
    28                 reject( e );
    29             }
    30         })
    31     }).catch( e => {
    32         log.error( e.message, "readFile" );
    33         throw new Error( code.fileSysError.code );
    34     });
    35 }

    3. axios进行http请求以及通过webpack设置代理(因为项目运行时前后端各占用一个端口)

    webpack也是通过http-proxy-middleware包实现http代理

    //跨域无法请求的时候我们可以修改工程下config文件夹下的index.js中的dev:{}部分。
    dev: {
        env: require('./dev.env'),
        port: config.devHotPort,
        autoOpenBrowser: true,
        assetsSubDirectory: 'static',
        assetsPublicPath: '/',
        proxyTable: {
            [config.proxyPrefix]: {
                target: 'http://localhost:' + config.port,
                changeOrigin: true,
                pathRewrite: {
                    ['^'+config.proxyPrefix]: ''
                }
            }
        },
        cssSourceMap: false
      }
    }
     1 //在开发环境中进行配置,不能为空字符串,不然前端不会热更新,只会请求服务端代码,配置代理从而前后端都能热加载,生产环境记得改为“”;
     2 axios.interceptors.request.use(function(config) {
     3         if(globalConfig.proxyPrefix){
     4             config.url = globalConfig.proxyPrefix + config.url;
     5         }
     6         return config;
     7     },
     8     function(error) {
     9         // Do something with request error
    10         return Promise.reject(error);
    11     }
    12 );

    安装其他插件的时候,可以直接在 main.js 中引入并 Vue.use(),但是 axios 并不能 use,只能每个需要发送请求的组件中即时引入;

    为了解决这个问题,有两种开发思路,一是在引入 axios 之后,修改原型链;二是结合 Vuex,封装一个 aciton。

    import axios from 'axios'
    Vue.prototype.$ajax = axios
    
    //然后可以在组件中调用
    this.$ajax({
        method  : 'post',
        url     : '/Interface/getSight',
        data    :  {}
    }).then( result => {
        switch(result.data.retcode){
            case 0:
                for(let i = 0; i < result.data.retdata.length; i++){
                    self.sightStatus.push(false);
                }
    
                self.sightList = result.data.retdata;
                break;
        }
    }).catch( err => {
        console.log(err)
    })

     4. node作为代理服务器(中间层)

    vue-cli 的npm start 执行的脚本是 "npm run dev",所以和开发环境一样,上生产中,我们可以用niginx做代理服务器进行分发,在这个项目中,直接用node做代理服务器

      1 /**
      2  * 作为代理服务器接口,暂未对data进行buffer二进制处理
      3  * @version 2017-05-29
      4  * @param   {string}        url         请求链接
      5  * @param   {object}        data        请求参数
      6  * @param   {string}        method      请求类型
      7  */
      8 proxyRequest( req, res, url, data, method = "post"){
      9 
     10     let options, httpClient, tempOptions;
     11     tempOptions = urlParser.parse(config.serverUrl + url)
     12     options = {
     13         hostname    :   tempOptions.hostname,
     14         port        :   tempOptions.port,
     15         path        :   tempOptions.pathname,
     16         method      :   method,
     17         encoding    :   "utf-8"
     18     }
     19     options.headers = req.headers;
     20     //默认传递json数据
     21     data = JSON.stringify( data );
     22 
     23     switch( req.protocol ){
     24         case "http:":
     25             httpClient  =   httpNative;
     26         break;
     27 
     28         case "https:":
     29             httpClient  =   httpsNative;
     30         break;
     31 
     32         default:
     33             httpClient  =   httpNative;
     34     }
     35 
     36     return new Promise( ( resolve, reject ) => {
     37         let request = httpClient.request( options, function( response ){
     38             if( response.statusCode !== 200 ){
     39                 reject( new Error( "httpReuest error, status : " + response.statusCode ) );
     40             }
     41             let result, buf, bufArr, bufLen;
     42             result  =   {
     43                 httpVersion     :   response.httpVersion,
     44                 httpStatusCode  :   response.statusCode,
     45                 headers         :   response.headers,
     46                 body            :   "",
     47                 trailers        :   response.trailers
     48             };
     49             bufArr  =   [];
     50             bufLen  =   0;
     51             return response.on( "data", function( chunk ){
     52                 bufArr.push( chunk );
     53                 bufLen  +=  chunk.length;
     54             }).on( "end", function(){
     55                 try{
     56                     buf     =   Buffer.alloc( bufLen );
     57                     for( let i = 0, pos = 0; i < bufArr.length && pos < bufLen; i++ ){
     58                         bufArr[ i ].copy( buf, pos );
     59                         pos     +=  bufArr[ i ].length;
     60                     }
     61                     //必须返回全部信息才能让客户端和服务器创建连接
     62                     //resolve( JSON.parse( buf.toString() ) );
     63                     result.body     =   buf.toString();
     64                     resolve( result );
     65                 }catch( e ){
     66                     reject( e );
     67                 }
     68             });
     69         });
     70 
     71         request.on( "error", error => {
     72             log.error( "request : " + error.message, "Http" );
     73             reject( error );
     74         });
     75 
     76         if( data !== null ){
     77             request.write( data );
     78         }
     79 
     80         request.end();
     81     }).catch( e => {
     82         log.error( e.message, "Http" );
     83         throw new Error( code.httpError.code );
     84     }).then( result => {
     85         let body = JSON.parse(result.body);
     86 
     87         //必须把把响应头返回给客户端
     88         for(let item in result.headers){
     89             res.set(item, result.headers[item])
     90         }
     91         switch( body.retcode ){
     92             case 0:
     93                 result.body = body.retdata;
     94             break;
     95 
     96             case -1:
     97                 this.paramError( body.retmsg );
     98             break;
     99 
    100             default:
    101                 throw new Error( body.retcode );
    102         }
    103         return result;
    104     })
    105 }
    1 return this.proxyRequest(req, res, "/user/editUserInfo", {}).then( result => {
    2     return {
    3         data : result.body,
    4         str  : "修改用户信息"
    5     }
    6 })

    在本教程中,采用JWT登录验证,但不打算把后端项目放到GitHub上,所以不使用this.proxyRequest进行请求,而是this.request, 然后把JWT放在中间层进行处理

    5. vuex状态管理

    6. 富文本编辑器的选择(vue-quill-editor)

    1 npm install vue-quill-editor
    2 npm install quill
    1 import 'quill/dist/quill.core.css'
    2 import 'quill/dist/quill.snow.css'
    3 import VueQuillEditor from 'vue-quill-editor'
    4 
    5 Vue.use(VueQuillEditor)//main.js中全局引入

    将其封装成一个组件

    https://surmon-china.github.io/vue-quill-editor/ 官方demo给了几个例子给你快速上手

    quill-image-resize-module
    //用于图片resize,直接按照3.0版本在我自己实际开发过程中报modules undefined
    //后面我直接引入1.0版本的,则没有问题,需要可在github复制下来

    对于图片单独放到云服务器问题的,我是采用在后端处理解决的(参考:https://www.jianshu.com/p/36b144b4cef8)

  • 相关阅读:
    字符串的格式化操作
    了解格式化输出,字符串和编码
    面试题2
    面试题1
    设计算法1
    C++ STL容器的理解
    网络是怎样连接的-路由器的附加功能
    网络是怎样连接的-路由器的包转发操作(下)
    网络是怎样连接的-路由器的包转发操作(上)
    网络是怎样连接的-交换机的包转发操作
  • 原文地址:https://www.cnblogs.com/luguiqing/p/8508879.html
Copyright © 2020-2023  润新知