接着一的內容,我們繼續。之前準備工作以及舞臺數據等都準備好了。
接下來,先對單個圖片的佈局樣式設置好,在src/components的main.js裏添加如下代碼
//單個圖片組件
class ImgFigure extends React.Component{
render(){
return(
<figure className="img-figure" >
<img src={this.props.data.imageURL} alt={this.props.data.title} />
<figcaption>
<h2 className="img-title">{this.props.data.title}</h2>
</figcaption>
</figure>
);
}
}
然後在app.scss裏添加樣式,這個是在.img-sec下的,
.img-sec {
position: relative;
width: 100%;
height: 90%;
overflow: hidden;
background-color: #ddd;
/*****添加代碼*******/
@at-root{
.img-figure{
position: absolute;
width: 320px;
height: 360px;
margin: 0;
padding: 40px;
background-color: #fff;
box-sizing: border-box;
}
figcaption{
text-align: center;
.img-title{
margin:20px 0 0 0;
color: #a7a0a2;
font-size: 16px;
}
}
}
}
效果如下圖
到了這裏圖片會順序排到底部。我們接下來分析照片牆位置,獲取所有的位置信息。這裏也是按照慕課網分析的寫的。
在main.js 裏的AppComponent組件裏添加函數如下,代碼中的rearrange函數爲重新排布位置函數,後續有相關補充。
componentDidMount(){
/**舞臺的寬高以及半寬半高**/
var stageDOM = React.findDOMNode(this.refs.stage),
stageW = stageDOM.scrollWidth,
stageH = stageDOM.scrollHeight,
halfStageW = Math.ceil(stageW/2),
halfStageH = Math.ceil(stageH/2);
//圖片的寬高以及半寬半高
var imgDOM = React.findDOMNode(this.refs.imgFigure0),
imgW = imgDOM.scrollWidth,
imgH = imgDOM.scrollHeight,
halfImgW = Math.ceil(imgW/2),
halfImgH = Math.ceil(imgH/2);
/**中央圖片的位置**/
this.Constant.centerPos = {
left: halfStageW - halfImgW,
top: halfStageH - halfImgH
};
/**水平方向上左右兩側圖片範圍start**/
/**左**/
this.Constant.hPosRange.leftSecX[0] = -halfImgW;
this.Constant.hPosRange.leftSecX[1] = halfStageW - halfImgW * 3;
/**右**/
this.Constant.hPosRange.rightSecX[0] = halfStageW + halfImgW;
this.Constant.hPosRange.rightSecX[1] = stageW - halfImgW;
/**垂直**/
this.Constant.hPosRange.h_y[0] = -halfImgH;
this.Constant.hPosRange.h_y[1] = stageH - halfImgH;
/**水平方向上左右兩側圖片範圍end**/
/**垂直方向上頂部圖片範圍start**/
this.Constant.vPosRange.v_x[0] = halfStageW - imgW;
this.Constant.vPosRange.v_x[1] = halfStageW;
this.Constant.vPosRange.v_y[0] = -halfImgH;
this.Constant.vPosRange.v_y[1] = halfStageH - halfStageH*3;
/**垂直方向上頂部圖片範圍end**/
/**默認居中第一章圖片**/
this.rearrange(0);
}
當然,這裏需要在AppComponent裏添加Constant變量,不能按照視頻裏的寫,因爲此處用的是ES6的模式的寫的react,所以按照視頻裏的步驟會報錯。
在AppComponent組件裏直接聲明的變量無法獲取,應該在AppComponent裏添加constructor(props) 函數,代碼如下
constructor(props) {
super(props);
/***位置範圍常量***/
this.Constant= {
centerPos:{
left:0,
top: 0
},
hPosRange:{
leftSecX:[0,0],
rightSecX:[0,0],
h_y:[0,0]
},
vPosRange:{
v_x:[0,0],
v_y:[0,0]
}
};
}
所有位置獲取之後,我們得給圖片一個放置位置的地方,需要初始化一個對象,按照視頻裏的代碼如下
//初始化數據
getInitialState(){
//初始化圖片位置信息
return({
imgsArrangerArr:[]
});
}
在render裏添加
var controllerUnits=[],
that = this,
imgFigures=[];
imageDates.map(function(value,index){
//如果圖片的位置信息不存在的話,初始化所有圖片位置
if (!that.state.imgsArrangeArr[index]) {
that.state.imgsArrangeArr[index]={
pos:{
left:0,
top:0
}
}
}
imgFigures.push(<ImgFigure key={index} data={value} arrange={this.state.imgsArrangeArr[index]} ref={'imgFigure'+index} />);
}.bind(this));
但是運行之後會提示錯誤:
Warning: getInitialState was defined on DimensionPicker, a plain JavaScript
class. This is only supported for classes created using React.createClass. Did
you mean to define a state property instead?
這是因爲在ES6的classes裏面getInitialState函數已經拋棄,我們設置state需在constructor函數裏面。刪除getInitialState修改如下:
constructor(props) {
super(props);
this.state = { imgsArrangeArr: []};
this.Constant= {
centerPos:{
left:0,
top: 0
},
hPosRange:{
leftSecX:[0,0],
rightSecX:[0,0],
h_y:[0,0]
},
vPosRange:{
v_x:[0,0],
v_y:[0,0]
}
};
}
接下來,我們按照視頻裏的分析,寫出了rearrange函數,代碼如下:
var imgsArrangeArr = this.state.imgsArrangeArr, //獲取圖片位置信息數組
Constant = this.Constant, //獲取定位位置對象
centerPos = Constant.centerPos, //獲取 居中位置信息
hPosRange = Constant.hPosRange, //獲取 水平位置信息
h_leftSecX = hPosRange.leftSecX, //獲取 左側x位置信息
h_rightSecX= hPosRange.rightSecX, //獲取 右側x位置信息
h_y = hPosRange.h_y, //獲取 y位置信息
vPosRange = Constant.vPosRange, //獲取 頂部位置信息
v_x = vPosRange.v_x, //獲取 頂部x位置信息
v_y = vPosRange.v_y; //獲取 頂部y位置信息
//獲取居中圖片index並居中處理
var imgsArrangeArrCenter = imgsArrangeArr.splice(centerIndex,1);
imgsArrangeArrCenter.pos= centerPos;
//獲取頂部圖片index並處理
var topImgNum = Math.ceil(Math.random()*2),
topIndex = 0,
imgsArrangeArrTop = [];
if (topImgNum) {
topIndex = Math.ceil(Math.random()*(imgsArrangeArr.length-topImgNum+1));
imgsArrangeArrTop = imgsArrangeArr.splice(topIndex,topImgNum);
imgsArrangeArrTop.forEach(function(value,index){
imgsArrangeArrTop[index].pos={
left: getRangeRandom(v_x[0],v_x[1]),
top: getRangeRandom(v_y[0],v_y[1])
};
});
}
//獲取水平方向上的圖片信息並處理
var k = Math.ceil(imgsArrangeArr.length/2);
for (var i = 0; i < imgsArrangeArr.length; i++) {
if (i<k) {
imgsArrangeArr[i].pos = {
left: getRangeRandom(h_leftSecX[0],h_leftSecX[1]),
top: getRangeRandom(h_y [0],h_y [1])
}
}else{
imgsArrangeArr[i].pos = {
left: getRangeRandom(h_rightSecX[0],h_rightSecX[1]),
top: getRangeRandom(h_y [0],h_y [1])
}
}
}
//將取出的數組元素修改之後放回去
//頂部圖片
if (imgsArrangeArr && imgsArrangeArrTop) {
for (var i = topImgNum-1; i >= 0; i--) {
imgsArrangeArr.splice(topIndex,0,imgsArrangeArrTop[i]);
}
}
//中間圖片
imgsArrangeArr.splice(centerIndex,0,imgsArrangeArrCenter);
this.setState({
imgsArrangeArr: imgsArrangeArr
})
這裏稍微做了一下修改,按照視頻裏的頂部區域只能是0張或者1張照片,如果修改了隨機底數,大於1了,頂部的處理代碼無法滿足。
然後在main.js 裏添加getRangeRandom函數以及修改ImgFigure組件,代買如下
/*
* 取範圍內的隨機整數
* @param low,high
*/
function getRangeRandom(low,high) {
return Math.ceil(Math.random()*(high-low)+low);
}
//單個圖片組件
class ImgFigure extends React.Component{
render(){
var styleObj={};
//如果props屬性中指定了這張圖片的位置,則使用
if (this.props.arrange.pos) {
styleObj = this.props.arrange.pos;
}
return(
<figure className="img-figure" style={styleObj}>
<img src={this.props.data.imageURL} alt={this.props.data.title} />
<figcaption>
<h2 className="img-title">{this.props.data.title}</h2>
</figcaption>
</figure>
);
}
}
至此,照片牆應該能隨意展示了,但是運行之後又會報錯
_reactDom2.default.render is not a function
這裏是因爲componentDidMount組件中的findDOMNode出問題了。
當我們需要獲取 React 組件上某個 DOM 節點時,React 提供了 refs 方法方便我們快速引用。爲了方便我們使用,React 還「貼心」地對 refs 做了一層封裝,使用 this.refs.xxx.getDOMNode() 或 React.findDOMNode(this.refs.xxx) 可以獲取到真正的 DOM 節點。
結果發現大家真正需要的就是 DOM 節點本身,封裝了半天完全是浪費感情。
於是在 v0.14 版中 refs 指向的就是 DOM 節點,同時也會保留 .getDOMNode() 方法(帶 warning),最終在 v0.15 版中去除該方法。
之前要用
React.findDOMNode(this.refs.xxx)或者this.refs.xxx.getDOMNode() 獲取DOM節點
現在直接用
this.refs.xxx就能獲取
這是我在網上找到了,但是修改之後發現,組件上的ref定義之後用this.refs.xxx獲取的不是虛擬dom節點,獲取的是Compoennt實例,ref添加到原生HTML上獲取的纔是DOM,所以代買修改如下時會報錯..原因是imgDOM 獲取的是Compoennt實例,後面的imgW ,imgH 等無法獲取數值,是空的,所以報錯。
//舞臺的寬高以及半寬半高
var stageDOM = this.refs.stage,
stageW = stageDOM.scrollWidth,
stageH = stageDOM.scrollHeight,
halfStageW = Math.ceil(stageW/2),
halfStageH = Math.ceil(stageH/2);
//圖片的寬高以及半寬半高
var imgDOM = this.refs.imgFigure0,
imgW = imgDOM.scrollWidth,
imgH = imgDOM.scrollHeight,
halfImgW = Math.ceil(imgW/2),
halfImgH = Math.ceil(imgH/2);
經過幾番查找,終於找到如何將Compoennt實例轉化爲DOM節點了,
在main.js中需要在頂部添加
import ReactDOM from 'react-dom';
然後對imgDOM = this.refs.imgFigure0
修改如下
var imgDOM = ReactDOM.findDOMNode(this.refs.imgFigure0),
到這裏,照片牆能正常顯示。如下圖
今天就到這裏。