react学习资料九-reflux

Reflux

Reflux , flux , redux 都是处理React数据层面的一个框架(插件、库),定义了action , store 来传递数据的;
作用都一样,唯一的不同是提供的api不同,因此会使用一个,其他都会了;

项目实例

React项目目录结构:
css目录,是网站样式目录
bootstrap.css框架
index.less页面样式
data目录,模拟异步请求的假数据
fonts目录,里面的文件是bootstrap引用的字体文件
image目录里面有两个目录
banner目录是页面banner的背景图片
item目录是网站每个网址的北京图片
logo图片
js目录引用了4个库
jquery库是用来发送异步请求的
React库
React-router库
Reflux库
Index.jsx在这个文件中书写业务逻辑
Index.html文件是项目的入口文件
fis-conf.js文件是项目的编译配置文件

制作CSS3开场动画

对于一个盒子的边是不能交叉的,因此实现这种动画,我们就不能只用一个盒子,至少需要了两个盒子,伪类可以实现盒子,一个元素就有两个伪类,这样就可以实现两个元素了,对于元素我们可以对它进行投影,而且每个盒子的投影个数是没有限制的,因此可以在盒子的两端实现投影;对于投影与原元素的关系,元素的宽度高度决定投影的宽度和高度,因此想控制投影的宽高可以控制盒子的宽高实现;
我们要制作CSS3动画,就要找到动画关键帧;

在React的路由中定义路由的规则同其他代码库定义路由规则是一样的,
/:query 定义动态的路由参数;

Reflux
action store component

component可以调用action发送消息
action将该消息映射到store中
store根据消息不同对数据做相应的处理,并传递给component供组件渲染页面
第一个组件和最后一个组件不一定是同一个组件
这样就实现了不同组件之间的消息传递
对于最后一个组件想要接收消息
必须通过混合监听这个store

创建action用Reflux.createActions创建
参数是一个数组,数组中的每个成员表示这个action可以发送的消息
创建store用Reflux.createStrore创建
参数是一个对象,这个对象是用来描述这个store的,
对象有个属性叫listenables,值是一个数组,数组中每个成员是一个action,也就是说写在这个数组中的每个action发送的消息,都可以在store中监听,如果想监听这些action动作,就要在store的对象中定一个这些监听方法,注意这些监听方法是以"on"开头的;

//第一步创建action
var DemoAction = Reflux.createActions(['say']);
//第二步创建store
var DemoStore = Reflux.createStore({
    listenables:[DemoAction],
    onSay: function(msgs){
        console.log(msgs,111)
    }
})
DemoAction.say('hellossss');
hellossss 111

input通过hash来传导

goSearch:function(e){
            // console.log(e.keyCode)
            if(e.keyCode == 13){
                var val = e.target.value;
                ReactRouter.HashLocation.replace('/search/' + val)
            }
    }
(function(){
var bannerNum = 2;
var itemNum = 33;
var DataBase = [];//存放sites.json接口请求的数据,将该数据缓存在前端
var $loadProcessDOM = $('.load-process');
//监听type路由
var TypeAction = Reflux.createActions(['changeType']);
//
var TypeStore = Reflux.createStore({
    listenables:[TypeAction],
    onChangeType:function(query){
        // console.log(query,222)
        var result = [];
        DataBase.forEach(function(obj){
            // console.log(obj,111)
            if(obj.type == query){
                result.push(obj)
            }
        })
        this.list = result;
        this.trigger(this.list);
        // console.log(this.list)
    }
})
var mapObj = {//搜索到重复的obj就返回true
    filte:function(obj,result){
            return result.some(function(value,index){
                console.log(value == obj,3)
                return (value == obj)
            })
    }
}   

var SearchAction = Reflux.createActions(['searchSite']);
var SearchStore = Reflux.createStore({
    listenables:[SearchAction],
    onSearchSite:function(query){
        var result = [];
        DataBase.forEach(function(obj){
            for(var i in obj){
                if(obj[i].indexOf(query) > -1 ){
                    if( result.length == 0 || !mapObj.filte(obj,result)){
                        result.push(obj)
                    }
                }
            }
        })
    this.list = result;
    this.trigger(this.list);

    }
})
//getSiteList被Index组件,type组件,seach组件公用,我们可以提取出来
var getMethods = {
    getBgImgUrl:function(){
        return 'url(img/item/item' + parseInt( Math.random() * itemNum )+ '.jpg)'
    },
    getSiteList:function(){
        var me = this;
        var pros = 0;
        return this.state.list.map(function(obj,index,arrs){
            //观察数据结构:
            // "site": "http://www.iqiyi.com/?vfm=f_328_hao1",
            // "name": "爱奇艺高清",
            // "company": "爱奇艺",
            // "type": "movie",
            // "description": "看电影网站"
            // console.log( ( ( (index + 1)  / arrs.length ) * 100) )
            var processNum = ( ( (index + 1)  / arrs.length ) * 100) ;
            // console.log(pros,processNum )
                me.prcetipsShow(pros,processNum);
                pros = processNum;
            var bg = {
                backgroundImage: me.getBgImgUrl()
            }
                return(
                <li key={index} style={bg}>
                    <a href={obj.site}>
                    <div className="show-box">
                        <h1>{obj.name}</h1>
                    </div>
                    <div className="layer-box">
                        <p className="layer-company">公司:{obj.company}</p>
                        <p>类型:{obj.type}</p>
                        <p>描述信息:{obj.description}</p>
                    </div>
                </a>
                </li>
            )
            })
    },
    prcetipsShow:function(pros,processNum){
        // console.log(pros,processNum )
        $('.proceShow').css('width',pros+'%').stop().animate({'width':processNum +'%'},500)
    }
}
var Index = React.createClass({
    //混合
    mixins:[getMethods],
    getInitialState:function(){
        return {
            list:DataBase
        }
    },
    
    render:function(){
        return (
            <ul>{this.getSiteList()}</ul>)
    }

})
var Type = React.createClass({
    mixins:[Reflux.connect(TypeStore,'list'),getMethods],
    getInitialState:function(){
        return {
            list:[]
        }
    },
    render:function(){
        // console.log(this.state, 1111)
        return (
            <ul>{this.getSiteList()}</ul>
        )
    }
})
var Search = React.createClass({
    mixins:[Reflux.connect(SearchStore,'list'),getMethods],
    getInitialState:function(){
        return {
            list:[]
        }
    },
    render:function(){
        return (
            <div>{this.getSiteList()}</div>
        )
    }
})
var Header = React.createClass({
    goSearch:function(e){
            // console.log(e.keyCode)
            if(e.keyCode == 13){
                var val = e.target.value;
                ReactRouter.HashLocation.replace('/search/' + val)
            }
    },
    render:function(){
        return (
            <div>
                <div className="header-nav">
                    <a href="#/">![](img/logo.png)</a>
                    <ul className="nav nav-pills nav-justified">
                        <li>
                            <a href="#/type/movie">视频</a>
                        </li>
                        <li>
                            <a href="#/type/games">游戏</a>
                        </li>
                        <li>
                            <a href="#/type/news">新闻</a>
                        </li>
                        <li>
                            <a href="#/type/sports">体育</a>
                        </li>
                        <li>
                            <a href="#/type/buy">购物</a>
                        </li>
                        <li>
                            <a href="#/type/friends">社交</a>
                        </li>
                    </ul>
                    <input type="text" onKeyUp={this.goSearch}/>
                </div>
                <div className="header-banner">
                    <div className="protips">
                        <div className="proceShow"></div>
                    </div>
                </div>
            </div>
        )
    }
})

//每一次路由的改变都需要个相应的query

var App = React.createClass({
    resetData:function(){
        var path = this.props.routeState.path;
        var query = this.props.routeState.params.query;
        if(path.indexOf('/type/') == 0){
            TypeAction.changeType(query)
        }else if(path.indexOf('/search/') == 0){
            // console.log(query)
            SearchAction.searchSite(query)
        }

    },
    render:function(){
        this.resetData();
        //打印属性状态,查看路由状态
        // console.log(this.props)
        var query = this.props.routeState.params.query;
        // console.log(query)
        return (
            <div>
                <Header></Header>
                <div  className="container main">
                <ReactRouter.RouteHandler />
                    
                </div>
            </div>

            )
    }
})

var Route = React.createFactory(ReactRouter.Route);
var DefaultRoute = React.createFactory(ReactRouter.DefaultRoute);
var routes = (
        <Route path="/" handler={App}>
            <Route path="/search/:query" handler={Search}></Route>
            <Route path="/type/:query" handler={Type}></Route>
            <DefaultRoute handler={Index}></DefaultRoute>
        </Route>
    )
//为了提高打开页面的预览效果,我们要将页面中用到的大图片加载出来;
/* 加载图片类
*   @params 表示加载图片的选项数据
*   @step 加载完每一张图片时候的回调函数
*   @success 全部加载完毕时候的回调函数
*   @fail 某张图片加载失败时候的回调函数
*   
**/
function ImageLoader(params,step,success,fail){
    //表示banner图片数
    this.bannerNum = params.bannerNum;
    //表示每一个网址的背景图片
    this.itemNum = params.itemNum;
    //总和
    this.totalNum = this.bannerNum + this.itemNum;
    this.step = step;
    this.success = success;
    this.fail = fail;
    //在这里开始加载图片
    this.loader()


}
ImageLoader.prototype = {
    loader:function(){
        //第一步加载banner图片
        var bannerNum = this.bannerNum;
        while (--bannerNum >= 0){
            this.loaderImg(bannerNum,true)
        }
        //第二步加载网址背景图片
        var itemNum = this.itemNum;
        while (--itemNum >= 0){
            this.loaderImg(itemNum)
        }
    },
    //加载一张图片
    /*@num加载图片的序号
    * @isBanner这张图片是否是banner图片
    ***/
    loaderImg:function(num,isBanner){
        var me = this;
        var img = new Image();
        img.onload = function(){
            //每次图片加载完成会执行step函数,但是不能一直执行,最后一次执行success;我们要判断图片是否全部加载完成;
            //判断图片是否全部加载完成,我们可以在每加载一张图片的时候对bannerNum和itemNum减一,直到这个数为0,我们执行success回调函数;
            if(isBanner){
                me.bannerNum--;
            } else {
                me.itemNum--;
            }
            //当bannerNum以及itemNum都是零的时候,我们执行success,否则我们执行step,继续执行
            if(me.bannerNum === 0 && me.itemNum === 0){
                me.step(me.bannerNum, me.itemNum, me.totalNum)
                me.success()
            }else{
                me.step(me.bannerNum, me.itemNum, me.totalNum)
            }
        }
        //当图片加载失败我们执行fail方法
        img.onerror = function(){
            if(isBanner){
                me.bannerNum--;
            } else {
                me.itemNum--;
            }
            me.fail(num,isBanner);
        }
        if(isBanner){
            img.src = me.getBannerImgUrl(num);
        } else {
            img.src = me.getItemImgUrl(num);
        }

    },
    getBannerImgUrl:function(num){
        return 'img/banner/banner'+num+'.jpg';
    },
    getItemImgUrl:function(num){
        return 'img/item/item' + num + '.jpg';
    }
}

//请求异步接口数据
$.get('data/sites.json',function(res){
        // console.log(res)
        if(res && res.errno === 0){
            DataBase = res.data;
            new ImageLoader({
                bannerNum:bannerNum,
                itemNum:itemNum
            },function(bannerNum,itemNum,totalNum){
                $loadProcessDOM.html(((totalNum - bannerNum - itemNum) / totalNum * 100).toFixed(2));
            },function(){
                console.log('success')
                setTimeout(function(){
                    //我们可以通过回调函数的第二个参数获取路由的状态,如何从组建中获取呢?
                    ReactRouter.run(routes,function(Handler,states){
                        // console.log(states) // params{query:xxxx} 可以通过属性props传递 在App父组件类中通过this.props.routeState来获取
                        React.render(<Handler routeState={states}></Handler>,$('#app')[0])
                    })
                },700)
                
            },function(num,isBanner){
                console.log('fail',num,isBanner)
                setTimeout(function(){
                    $('#app').html('success')
                    React.render(<App />,$('#app')[0])
                },700)
            })
        }
})  
//测试imageloader

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

推荐阅读更多精彩内容