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
})()