Fork me on GitHub

向前,向前进

看到vue2更新许久,一直没时间弄这些,年底有时间终于有空一探究竟了。
现在负责的公司的产品,正好想把技术栈更新一下,所以原型基于该产品,进行一下升级前的尝试和初步设计。

Vuex

我把store的mutations和actions都写了一起,但实际的项目还是尽量耦合度低一下,但后期你的项目状态多了以后,你的
store的维护成本会越来越大。

index.js

import Vue from 'vue';
import VueRouter from 'vue-router';
import Vuex,{ Store } from 'vuex';
//一定要在创建根组件之前use
Vue.use(Vuex);
import storeObj from './store.js'
const store = new Store(storeObj);
//创建根组件
new Vue({
    router,
    store,
    el:"#app",
    template:'<App />',
    components: { App }
});

store.js

state

通过vuex存储的应用状态

state: {
        loading:true,
        canscroll:true,
        nodata:false,
        nodata_text : "暂无更多数据",
        listdata:[]        
}

mutations

vuex的状态值只能通过mutation进行更新,而且mutations中必须是同步的

mutations : {
        loading (state, newState) {
            state.loading = newState;
        },
        canscroll (state, newState) {
            state.canscroll = newState;
        },
        nodata (state, newState) {
            state.nodata = newState;
        },
        nodata_text (state, newState) {
            state.nodata_text = newState;    
        },
        listdata (state, newData) {
            state.listdata = state.listdata.concat(newData);
        },
        timedown2process (state,{ i,disabled,showtype,status }){
            state.listdata[i].disabled = disabled;
            state.listdata[i].showtype = showtype;
            state.listdata[i].status.value = status.value;
        },
        updateText(state, { text, i }){
            state.listdata[i].status.value.text = text;
        }
}

actions

异步操作更新可以放到action中,通过commit进而更新state

actions : {
    loading (context,bool) {
        context.commit('loading',bool);
    },
    canscroll (context,bool) {
        context.commit('canscroll',bool);
    },
    nodata (context,bool) {
        context.commit('nodata',bool);
    },
    nodata_text (context,text) {
        context.commit('nodata_text',text);
    },
    listdata (context,{ page , compiler }) {                
        api.getListData(page).then(function(data){                
            let jsonData = $.parseJSON(data);
            if(jsonData.length < 10) {           
                context.commit('canscroll',false);
                context.commit('nodata',true);
                context.commit('nodata_text','暂无更多数据');
            }
            context.commit('loading',false);
            jsonData = jsonData.map(compiler);
            context.commit('listdata',jsonData);
            context.commit('canscroll',!context.state.nodata);
        });
    },
    timedown2process ({ commit },obj) {
        commit('timedown2process',obj);
    },
    updateText({ commit },obj){
        commit('updateText',obj);
    }
}

getters

一些get方法,获取应用的state信息

getters:{
    getLoading (state) {
        return state.loading;
    },
    canscroll (state) {
        return state.canscroll;
    },
    nodata (state) {
        return state.nodata;
    },
    nodata_text (state) {
        return state.nodata_text;
    },
    listdata (state){
        return state.listdata;
    }
}

Router

在router.js中配置好所有的路由信息,当然也可以通过细化模块的方式生成最终的router.js

module.exports = {
    mode:'history',
    routes:[
        {
            path:'/',
            component: Index
        }
    ]
};

index.vue

终于来到了首页组件,把首页拆分为一个个组件,尽量编写可复用的组件,这不就是模块化的方便之处么!

<template>
    <div class="content">
        <Slider></Slider>
        <List></List>
        <listLoading></listLoading>
        <listStatus></listStatus>
    </div>
</template>
<style scoped>
    .content{
        margin-top: 3rem;
    }
</style>
<script>
import Slider from './index/slider.vue';
import List from './index/list.vue';
import listLoading from './index/list_loading.vue';
import listStatus from './index/list_status.vue';
export default {
    components:{
        Slider,
        List,
        listLoading,
        listStatus
    }
}
</script>   

我眼中的产品

了解公司业务,根据业务实际情况,总结提炼出产品的流程逻辑,据此画出响应的原型,提供给设计开发,进行产品实现。
但是实际的产品应该是什么样的呢?

书中我读到的产品印象

了解需求,了解用户

讨论在一个产品的需求、用户痛点和体验的时候,还原到场景里面,看看用户当时的需求,并且了解此时的动机,来看产品
是否满足用户的需求。在用户行为分析,产品体验报告,用户研究上多做工作

产品的使用者就是用户,所以产品设计的出发点就是用户,需要调研和分析了用户行为以后,做出初代产品,邀请一些用户来使用
吐槽(例如公司同事),然后迭代完善。

懂技术和产品思维

产品经理懂技术,在出现线上问题以后,可以快速找到对应的开发,是找前端,PHP或者JAVA,可以降低沟通的成本,提高效率,而且
懂一些技术,可以功能实现的方式哈,不容易被忽悠哈。

产品思维在结构上分为:
1、规划分解
2、调研设计
3、项目管理
4、方案评估

小白产品

前期的产品经理首要的要多使用一些市面上成熟的产品,微信、QQ、淘宝这些我们常用是不够的,要多多使用,多多下载,多多分
析,体会此款产品的流程,在细节上的把控和产品迭代周期等等。

X > 好用的产品 > 好看的产品,so X = ‘好看又好用的产品’;

黑盒子模型

黑盒子是T行结构,通过这个盒子,用户从哭脸到笑脸,同时从底下掉出钱来。

互联网产品的第一价值的是微笑价值,然后才能带来商业价值。

服务用户爽到掏银子

观察和认识产品

第一看外观,
第二看结构;

首先是黑箱分析,看产品有没有达到预期成果,有没有带来微笑价值
白箱是去分析产品的流程、交互、原型和版本的迭代.

(未完待续)

Redux

Redux是由flux衍生而来的状态管理器,应用于大型的React应用,Redux会让React中的state变的可预测,网络有大量的Redux的教程,详细的介绍了redux的基础概念,
应用场景以及高级应用。
Redux有以下几个基础方面需要大家了解:
1、store
在redux中只有一个单一的store,我所理解的store就是应用的数据结构。
2、action
当用户做页面上做一些交互行为的时候,这时可以被描述为redux中的action。
3、reducer
我理解的reducer是对action(s)的提炼,然后switch-case的处理,它是一个纯函数,返回对应action行为进一步处理后的state,当然可以有多个reducer啦。

Store

//引入一个数据源
import { createStore } from 'redux'      
import rootReducer from './reducer/index'        
import events from './data/event';        
//设置一个默认的数据结构
const defaultState = {
    events:events
};
//创建一个Store实例(reducer,defaultState)
const store = createStore(rootReducer,defaultState);    
export default store;

Action

//回车创建一个todo  
export function createEvent (title,eventid,complete){
    return {
        type:"CREATE_EVENT",
        title,
        eventid,
        complete
    }
}
//点击圆圈标识是否完成
export function toggleStatusComplete(i){
    return {
        type:"TOGGLE_STATUS_COMPLETE",
        i
    }
}
//删除一个todo
export function removeEvent(i){
    return {
        type:"REMOVE_EVENT",
        i
    }
}

Reducer

index.js

 //redux提供了一个combineReducers,可以把多个reducer合为一个rootReducer
import { combineReducers } from 'redux'
import events from './events'
const rootReducer = combineReducers({events})
export default rootReducer

events.js

/*
*events中存在许多的actionType
*对应不同的action,进行不同的数据操作,返回不同的state信息
*/
export default function events(state, action){
    var i;
    switch (action.type) {
     case "CREATE_EVENT":
         console.log("create Event at here");
         return [
             ...state.slice(0),
             {title:action.title,eventid:action.eventid,complete:action.complete}
         ];
     case "TOGGLE_STATUS_COMPLETE":
         console.log("TOGGLE_STATUS_COMPLETE at here");
         i = action.i;
         return [
             ...state.slice(0,i),
             {...state[i],complete:!state[i].complete },
             ...state.slice(i+1)
         ];
     case "REMOVE_EVENT":
         console.log("REMOVE_EVENT at here");
         i = action.i;
         return [
             ...state.slice(0,i),
             ...state.slice(i+1)
         ];
     default:
         return state;
    }
}

@Github -> Redux-todo
@Redux中文API
@Learn Redux

Webpack with React


简单说webpack是一个module加载器,可以把项目内html,js,css以模块化的方式加载进项目内。
提供了很多的loader用于加载、解析不同的lib 或者 frame。
提供了许多plugin,实现诸如全局变量、模块热替换等功能。

总之是相当的全面,可以实现大部分前端工程化、模块化的功能

Hot Module Replacement


HMR意思是模块热替换(字面翻译哈哈),就是你在代码中修改代码,无需在浏览器中刷新,能够自己的更新浏览器中的代码,直接呈现在你的面前,解放你的双手,节省你的键盘。

实现方式

首先你要自己build一个项目,配置好你webpack.config,然后写一个简单的module。
你会在这之中看到Hot Module Replacement 的相关实现方式,大家也可以试试。
这里主要讲的是另外的实现方式哈。

server.js

/*
    path NodeJs Api 用于操作目录对象
    webpack
    dev-server 其实搭建了一个小型的express项目
    config 是你的webpack配置文件
*/
var path = require('path');
var webpack = require('webpack');
var express = require('express');
var config = require("./webpack.dev.config");

/*
    app 获取一个express的实例
    compile 返回一个Compiler实例
    webpack-dev-middleware            
    webpack hot middleware
    用来实现热替换的中间件
    app.get('*'…… 配置路由        
    最后启用端口监听        
*/
var app = express();
var compile = webpack(config);

app.use(require('webpack-dev-middleware')(compile,{
    noInfo: true,
    publicPath: config.output.publicPath
}));

app.use(require('webpack-hot-middleware')(compile,{
    log: console.log, path: '/__webpack_hmr', heartbeat: 10 * 1000
}));

app.get('*',function(req, res){
    res.sendFile(path.join(__dirname,'index.html'));
});

app.listen(8000,'127.0.0.1',function(){});

webpack.dev.config.js

var webpack = require("webpack");
var path = require("path");
var config = {
    devtool: 'source-map',
    //  app 获取一个express的实例
    //  compile 返回一个Compiler实例
    //  webpack-dev-middleware            
    //  webpack hot middleware
    //  用来实现热替换的中间件
    //  app.get('*'…… 配置路由        
    //  最后启用端口监听        
    entry:[
        'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000&reload=true',
        __dirname + '/src/entry.js'
    ],
    /*
         这里需要注意一下,
         运行node server.js时不会生成文件到dist中,需要运行build进行构建才会生成
         其次,配置的filename在你的项目中找不到的,
         要想使用entry.js,在html中引用地址写成'/static/entry.js'是可以引用到的
    */
    output: {
        path:path.resolve(__dirname,'dist'),
        filename: "entry.js",
        publicPath:"/static/"
    },
    /*
        new webpack.optimize.OccurenceOrderPlugin(),
        为组件分配ID,通过这个插件webpack可以分析和优先考虑使用最多的模块,并为它们分配最小的ID
        new webpack.HotModuleReplacementPlugin()
        这个就是实现HMR的plugin
        new webpack.NoErrorsPlugin()
        发现错误不打断程序
    */
    plugins: [
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin()
    ],
    module:{
        loaders:[
            /*
               babel加载器
               exclude除去的意思
               query的preset,进行es2015,react加载?
               test: A condition that must be met
               exclude: A condition that must not be met
               include: An array of paths or files where the imported files will be transformed by the loader
               loader: A string of “!” separated loaders
               loaders: An array of loaders as string
             */
            {
                test:/\.js$/,
                exclude:/(node_modules)/,
                loader:'babel-loader',
                include: path.join(__dirname, 'src'),
                query:{
                    presets:['es2015','react']
                }
            }
        ]
    }
}
module.exports = config;

OK,现在执行,可以看到页面出现在大家面前,修改自己的module文件发现页面刷新了,貌似这个跟咱们预想的不太一样耶

一顿寻找中…

发现了react-transform

在root下建立一个.babelrc

.babelrc

首先安装

npm install react-transform --save && npm install react-transform-hmr --save

然后配置.babelrc

{
  "presets": ["react", "es2015"],
  "env": {
    "development": {
      "plugins": [
        ["react-transform", {
          "transforms": [{
            "transform": "react-transform-hmr",
            "imports": ["react"],
            "locals": ["module"]
          }]
        }]
      ]
    },
    "production": {
      "plugins": []
    }
  }
}

Perfect !!!
@GitHub webpack-dev-middleware
@手把手深入理解 webpack dev middleware 原理與相關 plugins
@babel-plugin-react-transform

浏览器工作流程

1:解析HTML,重建DOM树
2:解析CSS,构建渲染树
3:从根节点递归调用,布局渲染树
4:遍历渲染树,每个节点将使用UI后端层来绘制

PS: css引擎是按照每条规则从右到左的顺序去匹配

CSS性能提升方案

1:避免使用通配规则
2:尽量少的区对标签进行选择,而是用class
3:不要去用标签先定ID或者类选择符
4:尽量少的去使用后代选择器,降低选择的权重值
5:考虑继承

NodeJs — NodeMailer

/*安装一下Module*/
npm install -g nodemailer

/*引用一下*/
var nodemailer = require("/xx/xx/nodemailer");


var transporter = nodemailer.createTransport({
        service:'Gmail',
        auth:{
        /*你的邮箱地址*/
            user:'xxx@xxx.com',
        /*密码*/
            pass:'xxxx'
        }
    });

/*
  to:收件人的邮箱地址,
  html:邮件html内容
*/

var mailOptions = {
    from:"",
    to:"wangshengcai@hexindai.com,yaoaiyang@hexindai.com",
    text:"helloword",
    html:"<b>Hello world</b>"
}
/*粗发*/
transporter.sendMail(mailOptions, function(error, info){
    if(error){
        return console.log(error);
    }
    console.log('Message sent: ' + info.response);

});

然后在terminal里node这个js就OK了

执行后会遇到两个问题

  1. [Error: Invalid login] code: ‘EAUTH’…………
    因为用的是gmail,所以去账户里 允许不够安全的应用访问
  2. { [Error: Connection timeout] code: ‘ETIMEDOUT’ }
    这里我把代理管理就好了,估计是很网络协议有关^_^。。。

安装SASS

由于SASS是基于RUBY开发的,所幸MAC已经预装了RUBY,所以直接在终端输入

sudo gem install sass -V

PS: -V 可以查看安装的进程

安装Compass

Compass是一个样式框架,里面包括了大量定义好的mixin,函数,以及对SASS的扩展,并且貌似还提供了好多插件,想生成开发版、发布版。
HOHO,from 百度百科,据说学会了Compass,CSS的开发效率可以上一个台阶呢

sudo gem install compass -V

安装中遇到的问题

  1. mac 用户记得安装Xcode,要不无法正常安装,会报错的。
  2. 尽管你sudo了,但会有安装不成功的情况,例如
    You don't have write permissions for the /Library/Ruby/Gems/
    
    类似这样的问题,解决方法
    sudo gem install -n /usr/local/bin GEM_NAME_HERE
    

Mobile Web

head内的meta,写下备用

<!--user-scalable=no是需要的,发现在某些设备上仅有initial和maximum仍然无法阻止缩放 -->
<meta content="initial-scale=1,maximum-scale=1,user-scalable=no,width=device-width" name="viewport"/>

<!-- touch-icon在IOS中用于桌面图标 -->
<link href="https://github.com/fluidicon.png" rel="apple-touch-icon-precomposed">

<!-- 从桌面icon 启动 iOS Safari 是否进入全屏状态(App模式)yes|no -->
<meta content="yes" name="apple-mobile-web-app-capable"/>

<-- iOS Safari 全屏状态下的状态栏样式 default  |  black  |  black-translucent -->
<meta content="black-translucent" name="apple-mobile-web-app-status-bar-style" />

<!-- iOS 设备上禁止将数字识别为可点击的tel link -->
<meta content="telephone=no" name="format-detection">

《在移动浏览器中使用Viewport元标签控制布局》

《Viewport双城记》-1

《Viewport双城记》-2

Hammer.js是目前使用较广泛的一个事件库,没用过,回头用一下试试哈

weinre 远程调试

远程测试 例如:移动云测试中心,云测

  • 初始化hexo

    hexo init
    
  • 安装依赖

    npm install
    有时安装不成功,可以用 sudo npm install
    
    L..o..a..d..i..n..g…
  • 配置_config.yml达成自定

    title: *****
    subtitle:*****
    description:*****
    author: *****
    language:*****
    timezone:*****
    
  • 如果想发布到GITHUB上,配置如下,详情见http://pages.github.com

    deploy:
      type: git
      repo: https://github.com/******/******.github.io
      branch: master
    
  • 创建文章

    hexo new layout "your articlehexo name"
    layout 可不填写,自取默认值
    写文章的话要用markdown,以前木有接触过,也是现学现用的
    

    MarkDown网址

  • 生成静态文件

    hexo generate
    
  • 发布

    hexo deploy
    
  • OK