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)

 

posted @ 2018-03-05 14:42  潮哥  阅读(243)  评论(0编辑  收藏  举报