├── .babelrc
├── README.md
├── lib
└── index.js
├── package.json
└── src
├── index.js
└── shot.gif
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env", "react"]
3 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-mult-transition-image-view
2 |
3 | a graceful react component for image display.
4 |
5 | ----
6 | 一个react图片显示组件 [segmentfault 使用说明](https://segmentfault.com/a/1190000011762388)
7 |
8 | | 参数 | 描述 | |
9 | | ------------- |:-------------:| :----- |
10 | | width | 宽度 ( 可选 ) | 会被转换成 style 的 width height |
11 | | height | 高度 ( 可选 ) | |
12 | | animate | 动画 ( 可选 ) | 默认: 'none' , 设置 'fade' 会加入 动画 class img-animate 来实现过渡动画) |
13 | | mode | 模式 ( 可选 ) | 默认: style |
14 | | img | 模式 ( 必选 ) | 可以是 url:string , 或者 是 [] 图片列表 |
15 |
16 | **图片过渡**
17 | 通过传入 img: [ img_sml , img_big ] ,来实现 图片从低质量 过渡到高质量来 防止大图 加载慢引起的空白。
18 |
19 | **注意**
20 | 样式可以参考下面的 less 代码
21 |
22 |
23 | 
24 |
25 |
26 | ### UPDATE
27 | 1.0.5 fix component receive props can not update
28 |
29 |
30 | ----
31 | ### Use
32 |
33 | npm install react-mult-transition-image-view
34 |
35 | ### Sample code
36 |
37 | ```` react jsx
38 |
39 | import ImageBoxView from 'react-mult-transition-image-view'
40 |
41 |
51 | ````
52 |
53 |
54 |
55 | ### Style
56 |
57 | ```` less
58 | .c-img-box{
59 | display:inline-block;
60 | width: 320px;
61 | height: 200px;
62 | background: #f7f6f5;
63 | position: relative;
64 | .img-hold{
65 | overflow: hidden;
66 | background-size: cover;
67 | background-repeat: no-repeat;
68 | background-position: center;
69 | img{
70 | width:100%;
71 | height:100%;
72 | }
73 | &.img-animate{
74 | transition: opacity 0.5s;
75 | }
76 | }
77 |
78 | .img-cover{
79 | background: url('https://d.2dfire.com/om/images/menulist/7deb58da.default.png') no-repeat center/300px;
80 | background-color:#f0f0f0;
81 | }
82 |
83 | .img-cover,
84 | .img-hold,
85 | .img-hide{
86 | position: absolute;
87 | width: 100%;
88 | height: 100%;
89 | top:0;
90 | left:0;
91 | }
92 |
93 | .img-hide{
94 | opacity: 0;
95 | }
96 |
97 | }
98 | ````
99 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
8 |
9 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
10 |
11 | var _react = require('react');
12 |
13 | var _classnames3 = require('classnames');
14 |
15 | var _classnames4 = _interopRequireDefault(_classnames3);
16 |
17 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18 |
19 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
20 |
21 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
22 |
23 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
24 |
25 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
26 |
27 | // 计算 图片的 数量
28 | var img_count = 0;
29 |
30 | var ImageBoxView = function (_Component) {
31 | _inherits(ImageBoxView, _Component);
32 |
33 | function ImageBoxView(props) {
34 | _classCallCheck(this, ImageBoxView);
35 |
36 | var _this = _possibleConstructorReturn(this, (ImageBoxView.__proto__ || Object.getPrototypeOf(ImageBoxView)).call(this, props));
37 |
38 | _this.init = _this.init.bind(_this);
39 | _this.onFetchImg = _this.onFetchImg.bind(_this);
40 | _this.show = _this.show.bind(_this);
41 |
42 | _this._name = img_count++;
43 |
44 | var state = _this.init(props);
45 | _this.state = state;
46 | return _this;
47 | }
48 |
49 | _createClass(ImageBoxView, [{
50 | key: 'init',
51 | value: function init(props) {
52 | var img = props.img,
53 | _props$animate = props.animate,
54 | animate = _props$animate === undefined ? '' : _props$animate,
55 | _props$mode = props.mode,
56 | mode = _props$mode === undefined ? '' : _props$mode,
57 | _props$delay = props.delay,
58 | delay = _props$delay === undefined ? 0 : _props$delay,
59 | _props$wait = props.wait,
60 | wait = _props$wait === undefined ? 0 : _props$wait,
61 | _props$width = props.width,
62 | width = _props$width === undefined ? 0 : _props$width,
63 | _props$height = props.height,
64 | height = _props$height === undefined ? 0 : _props$height;
65 |
66 | var img_list = [];
67 |
68 | if (typeof img == 'string' && img.length > 0) {
69 |
70 | var img_item = {
71 | url: img,
72 | status: 0, // 0 no 1: ready
73 | fade: 0 };
74 |
75 | img_list.push(img_item);
76 | } else if ((typeof img === 'undefined' ? 'undefined' : _typeof(img)) == 'object' && img.length > 0) {
77 |
78 | img.map(function (item) {
79 | var img_item = {
80 | url: item,
81 | status: 0,
82 | fade: 0
83 | };
84 | img_list.push(img_item);
85 | });
86 | }
87 |
88 | var state = {
89 | show: false,
90 | img_list: img_list,
91 | animate: animate == 'fade',
92 | style_mode: mode == 'style',
93 | delay: parseInt(delay),
94 | wait: parseInt(wait),
95 |
96 | size: {
97 | width: parseInt(width),
98 | height: parseInt(height)
99 | }
100 | };
101 |
102 | return state;
103 | }
104 | }, {
105 | key: 'show',
106 | value: function show(flag) {
107 | this.setState({
108 | show: flag ? true : false
109 | });
110 | }
111 | }, {
112 | key: 'componentDidMount',
113 | value: function componentDidMount() {
114 | var _this2 = this;
115 |
116 | var delay = this.state.delay;
117 |
118 |
119 | if (delay) {
120 | this._timer = setTimeout(function () {
121 | _this2.show(1);
122 | }, delay);
123 | } else {
124 | this.show(1);
125 | }
126 | }
127 | }, {
128 | key: 'componentWillUnmount',
129 | value: function componentWillUnmount() {
130 | this._timer && clearTimeout(this._timer);
131 | }
132 | }, {
133 | key: 'componentWillReceiveProps',
134 | value: function componentWillReceiveProps(nextProps) {
135 | var img = nextProps.img;
136 |
137 | if (img != this.state.img_data) {
138 | var state = this.init(nextProps);
139 | state.show = true;
140 | this.setState(state);
141 | }
142 | }
143 | }, {
144 | key: 'onFetchImg',
145 | value: function onFetchImg(index) {
146 | var _this3 = this;
147 |
148 | var _state = this.state,
149 | _state$img_list = _state.img_list,
150 | img_list = _state$img_list === undefined ? [] : _state$img_list,
151 | _state$animate = _state.animate,
152 | animate = _state$animate === undefined ? false : _state$animate,
153 | _state$style_mode = _state.style_mode,
154 | style_mode = _state$style_mode === undefined ? false : _state$style_mode;
155 |
156 |
157 | var img_item = img_list[index];
158 | if (img_item == undefined) {
159 | return;
160 | }
161 |
162 | img_item.status = 1;
163 |
164 | if (style_mode) {
165 | img_item.style = {
166 | backgroundImage: 'url(' + img_item.url + ')'
167 | };
168 | }
169 |
170 | if (animate && index > 0) {
171 |
172 | var img_ref = 'img_' + index;
173 | var img_dom = this.refs[img_ref];
174 |
175 | var img_name = 'img_' + this._name + '_' + index;
176 |
177 | if (img_dom) {
178 | img_dom.addEventListener("webkitTransitionEnd", function () {
179 | img_item.fade = 1;
180 | _this3.setState({ img_list: img_list });
181 | });
182 | }
183 | } else {
184 | img_item.fade = 1;
185 | }
186 | this.setState({ img_list: img_list });
187 | }
188 | }, {
189 | key: 'onLoadImg',
190 | value: function onLoadImg(index) {
191 | var _this4 = this;
192 |
193 | var wait = this.state.wait;
194 |
195 |
196 | if (wait && index > 0) {
197 | // let delay = parseInt(Math.random() * 2000)
198 | this._timer = setTimeout(function () {
199 | _this4.onFetchImg(index);
200 | }, wait);
201 | } else {
202 | this.onFetchImg(index);
203 | }
204 | }
205 | }, {
206 | key: 'render',
207 | value: function render() {
208 | var _this5 = this;
209 |
210 | var _state2 = this.state,
211 | _state2$img_list = _state2.img_list,
212 | img_list = _state2$img_list === undefined ? [] : _state2$img_list,
213 | _state2$animate = _state2.animate,
214 | animate = _state2$animate === undefined ? false : _state2$animate,
215 | show = _state2.show,
216 | _state2$size = _state2.size,
217 | size = _state2$size === undefined ? {} : _state2$size;
218 |
219 |
220 | var is_show_cover = img_list.length == 0;
221 |
222 | var first = img_list[0];
223 | if (first) {
224 | is_show_cover = first.fade == 0;
225 | }
226 |
227 | var img_name = 'img_' + this._name;
228 |
229 | var className = this.props.className;
230 |
231 |
232 | var container_cls = (0, _classnames4.default)(_defineProperty({
233 | 'c-img-box': true
234 | }, className, className));
235 |
236 | var container_style = {};
237 |
238 | if (size.width) {
239 | container_style.width = size.width + 'px';
240 | }
241 | if (size.height) {
242 | container_style.height = size.height + 'px';
243 | }
244 |
245 | return React.createElement(
246 | 'div',
247 | { className: container_cls, style: container_style, ref: 'container' },
248 | is_show_cover && React.createElement('div', { className: 'img-cover' }),
249 | show && img_list.map(function (item, index) {
250 | var _item$url = item.url,
251 | url = _item$url === undefined ? '' : _item$url,
252 | _item$style = item.style,
253 | style = _item$style === undefined ? null : _item$style;
254 |
255 | if (index > 0) {
256 | var last = img_list[index - 1];
257 | // 如果 前面的图 还没加载好 则 不显示
258 | if (last && last.status == 0) {
259 | return null;
260 | }
261 | }
262 |
263 | if (index < img_list.length) {
264 | var next = img_list[index + 1];
265 | if (next && next.fade == 1) {
266 | return null;
267 | }
268 | }
269 |
270 | var ref = 'img_' + index;
271 |
272 | var img_cls = (0, _classnames4.default)(_defineProperty({
273 | 'img-hold': item.status,
274 | 'img-hide': !item.status,
275 | 'img-animate': item.status && animate
276 | }, ref, true));
277 |
278 | var is_show_img_dom = !style;
279 | return React.createElement(
280 | 'div',
281 | { ref: ref, className: img_cls, style: style, onLoad: _this5.onLoadImg.bind(_this5, index) },
282 | is_show_img_dom && React.createElement('img', { src: url })
283 | );
284 | })
285 | );
286 | }
287 | }]);
288 |
289 | return ImageBoxView;
290 | }(_react.Component);
291 |
292 | exports.default = ImageBoxView;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-mult-transition-image-view",
3 | "version": "1.0.5",
4 | "description": "a graceful react component for image display.",
5 | "main": "lib/index.js",
6 | "keywords": [
7 | "react"
8 | ],
9 | "scripts": {
10 | "test": "echo \"Error: no test specified\" && exit 1",
11 | "babel": "babel src/ -d lib/"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/qilei0529/react-mult-transition-image-view.git"
16 | },
17 | "files": [
18 | "lib/"
19 | ],
20 | "author": "qilei",
21 | "license": "ISC",
22 | "devDependencies": {
23 | "babel-preset-env": "^1.6.0",
24 | "babel-preset-react": "^6.24.1"
25 | },
26 | "dependencies": {
27 | "classnames": "^2.2.5"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 |
2 | import { Component } from 'react'
3 |
4 | import classnames from 'classnames'
5 |
6 | // 计算 图片的 数量
7 | let img_count = 0
8 |
9 | class ImageBoxView extends Component {
10 |
11 | constructor(props) {
12 | super(props);
13 |
14 | this.init = this.init.bind(this)
15 | this.onFetchImg = this.onFetchImg.bind(this)
16 | this.show = this.show.bind(this)
17 |
18 | this._name = img_count++
19 |
20 | let state = this.init(props)
21 | this.state = state
22 | }
23 |
24 | init( props ) {
25 |
26 | let { img , animate = '' , mode = '' , delay = 0 , wait = 0 , width=0, height=0 } = props
27 | let img_list = []
28 |
29 | if ( typeof img == 'string' && img.length > 0 ){
30 |
31 | let img_item = {
32 | url: img,
33 | status: 0, // 0 no 1: ready
34 | fade: 0, // 0 1: fade ready
35 | }
36 |
37 | img_list.push( img_item )
38 |
39 | }else if ( typeof img == 'object' && img.length > 0) {
40 |
41 | img.map( ( item ) => {
42 | let img_item = {
43 | url: item,
44 | status: 0,
45 | fade: 0
46 | }
47 | img_list.push( img_item )
48 | })
49 |
50 | }
51 |
52 | let state = {
53 | show: false,
54 | img_list: img_list,
55 | animate: animate == 'fade',
56 | style_mode: mode == 'style',
57 | delay: parseInt(delay),
58 | wait: parseInt(wait),
59 |
60 | size: {
61 | width: parseInt(width),
62 | height: parseInt(height)
63 | }
64 | };
65 |
66 | return state
67 | }
68 |
69 | show( flag ) {
70 | this.setState({
71 | show: flag ? true : false
72 | })
73 | }
74 |
75 | componentDidMount() {
76 | let { delay } = this.state
77 |
78 |
79 | if ( delay ) {
80 | this._timer = setTimeout(() => {
81 | this.show(1)
82 | } , delay)
83 | }else{
84 | this.show(1)
85 | }
86 | }
87 |
88 | componentWillUnmount() {
89 | this._timer && clearTimeout(this._timer)
90 | }
91 |
92 | componentWillReceiveProps(nextProps) {
93 | let { img } = nextProps
94 | if (img != this.state.img_data) {
95 | let state = this.init(nextProps)
96 | state.show = true
97 | this.setState(state)
98 | }
99 | }
100 |
101 | onFetchImg( index ) {
102 |
103 | let { img_list = [] , animate = false , style_mode = false } = this.state
104 |
105 | let img_item = img_list[index]
106 | if ( img_item == undefined ) {
107 | return
108 | }
109 |
110 | img_item.status = 1
111 |
112 | if ( style_mode ) {
113 | img_item.style = {
114 | backgroundImage:`url(${img_item.url})`,
115 | }
116 | }
117 |
118 | if( animate && index > 0 ) {
119 |
120 | let img_ref = 'img_' + index
121 | let img_dom = this.refs[img_ref]
122 |
123 | let img_name = 'img_' + this._name + '_' + index
124 |
125 | if( img_dom ) {
126 | img_dom.addEventListener("webkitTransitionEnd", () => {
127 | img_item.fade = 1
128 | this.setState({ img_list })
129 | })
130 | }
131 |
132 | }else{
133 | img_item.fade = 1
134 | }
135 | this.setState({ img_list })
136 | }
137 |
138 | onLoadImg( index ) {
139 |
140 | let { wait } = this.state
141 |
142 | if (wait && index > 0 ) {
143 | // let delay = parseInt(Math.random() * 2000)
144 | this._timer = setTimeout(()=> {
145 | this.onFetchImg(index)
146 | } ,wait)
147 | }else{
148 | this.onFetchImg(index)
149 | }
150 |
151 | }
152 |
153 | render() {
154 |
155 | let { img_list = [] , animate = false , show , size = {} } = this.state
156 |
157 | let is_show_cover = img_list.length == 0
158 |
159 | let first = img_list[0]
160 | if( first ) {
161 | is_show_cover = first.fade == 0
162 | }
163 |
164 | let img_name = 'img_' + this._name
165 |
166 |
167 | let { className } = this.props
168 |
169 | let container_cls = classnames({
170 | 'c-img-box' : true,
171 | [className] : className
172 | })
173 |
174 | let container_style = {}
175 |
176 | if( size.width ) {
177 | container_style.width = size.width + 'px';
178 | }
179 | if( size.height ) {
180 | container_style.height = size.height + 'px';
181 | }
182 |
183 | return (
184 |
185 | {
186 | is_show_cover && (
)
187 | }
188 | {
189 | show && img_list.map(( item , index ) => {
190 |
191 | let { url = '' , style = null } = item
192 | if( index > 0) {
193 | let last = img_list[index-1]
194 | // 如果 前面的图 还没加载好 则 不显示
195 | if ( last && last.status == 0 ) {
196 | return null
197 | }
198 | }
199 |
200 | if ( index < img_list.length ) {
201 | let next = img_list[index + 1]
202 | if( next && next.fade == 1 ) {
203 | return null
204 | }
205 | }
206 |
207 | let ref = 'img_' + index
208 |
209 | let img_cls = classnames({
210 | 'img-hold' : item.status,
211 | 'img-hide' : !item.status,
212 | 'img-animate' : item.status && animate,
213 | [ref] : true
214 | })
215 |
216 | let is_show_img_dom = !style
217 | return (
218 |
219 | {
220 | is_show_img_dom &&

221 | }
222 |
223 | )
224 | })
225 | }
226 |
227 | )
228 | }
229 | }
230 |
231 |
232 | export default ImageBoxView
--------------------------------------------------------------------------------
/src/shot.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qilei0529/react-mult-transition-image-view/b6307ae5e362b6aa5ec3dac603e9b15b0b1a2105/src/shot.gif
--------------------------------------------------------------------------------