Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
flex 模態(tài)框彈窗浮動(dòng)垂直水平居中
- position:fixed 定位
- 元素的位置相對(duì)于瀏覽器窗口是固定位置。
- 即使窗口是滾動(dòng)的它也不會(huì)移動(dòng);
HTML 代碼實(shí)例
```
前的文章講了可視窗口可改變位置大小(查看),本文介紹配合react-draggable來實(shí)現(xiàn)既可改變大小又可移動(dòng)位置的模態(tài)窗口實(shí)現(xiàn)。
實(shí)現(xiàn)后效果:
<script src="https://lf6-cdn-tos.bytescm.com/obj/cdn-static-resource/tt_player/tt.player.js?v=20160723"></script>
該實(shí)現(xiàn)過程旨在它拖拽改變大小和改變位置抽象出來,所以具體的布局由調(diào)用方來處理,后面會(huì)有使用示例。
可拖拽窗口(DragableWindow)
import React, {createRef, useEffect,useState } from 'react'
import Drag,{ControlPosition } from 'react-draggable';
import {Resizable} from 're-resizable';
import {resizeOnVertical} from './utils'
import useStyle from './style'
import {calculatePositionAlwaysShowInView} from './utils'
interface Point extends ControlPosition{
}
interface DragabeWindowProps{
width:number;
height:number;
children?:any;
dragContorlClassName?:string;
}
const DragableWindow : React.FC<DragabeWindowProps> = (props) =>{
const CONTAINER_MIN_HEIGHT = 504;
const {children} = props;
const [resizePosition,setResizePosition] = useState<Point>({x:0,y:0});
const [position,setPosition] = useState<Point|null>();
const [containerHeight,setContainerHeight] = useState<number>(CONTAINER_MIN_HEIGHT);
/**
* @param e {object} 事件源
* @param direction {string} 拖動(dòng)方向
* @param ref {dom} 拖動(dòng)的元素
* @param d {object} 移動(dòng)偏移量
*/
const onResize = (e:any, direction:any, ref:any, d:any) => {
/* resize 之前的值 */
let originX = resizePosition?resizePosition.x:0;
let originY = resizePosition?resizePosition.y:0;
/* 移動(dòng)的位移 */
let moveW = d.width;
let moveH = d.height;
/* 移動(dòng)的位移 */
let x = null;
let y = null;
/* 處理上邊緣 */
if (/left/i.test(direction)) {
x = originX - moveW;
y = originY;
setPosition({ x, y });
/* 處理左邊緣 */
} else if (/top/i.test(direction)) {
x = originX;
y = originY - moveH;
setPosition({ x, y });
} else {
setPosition(null);
}
if (x || y) {
ref.style.transform = `translate(${x}px, ${y}px)`;
}
}
const onResizeStop = (e:any, direction:any, ref:any, d:any) => {
if (position) {
setResizePosition(position);
}
if (resizeOnVertical(direction)) {
//setContainerHeight(containerHeight + d.height);
}
}
/**彈出窗口的蒙層樣式 */
const popContainer: React.CSSProperties = {
top: 0,
left: 0,
overflow: 'hidden',
position: 'fixed',
height: '100%',
width: '100%',
alignItems:'center',
flexDirection: 'column',
display:'flex',
zIndex: 301,
backgroundColor:'rgba(0, 0, 0, 0.5)',
}
const {width,height} = props;
const {dragContorlClassName} = props;
const [dragStartPosition,setDragStartPosition] = useState<ControlPosition | null>();
useEffect(()=>{
/*初始容器(可拖拽組件對(duì)于的dom元素)的高度 */
if(height > CONTAINER_MIN_HEIGHT){
setContainerHeight(height);
}
},[height]);
const onDragStart = () => {
dragStartPosition !== null && setDragStartPosition(null);
}
const onDragStop = (e:any, draggableData:any) => {
calculatePositionAlwaysShowInView(e, draggableData,(x,y) =>{
setDragStartPosition({x,y});
});
};
let popoverRef = createRef<HTMLDivElement>();
const {styles,cx} = useStyle();
return (
<>
{/**彈出窗口的蒙層 */}
<div style={popContainer}>
{/** handler屬性指定拖拽移動(dòng)生效的樣式類,因彈出窗口還可彈出窗口,其應(yīng)該具有唯一性,
* 這個(gè)設(shè)計(jì)旨把拖拽移動(dòng)和拖拽改變大小抽象出來,通常拖拽部分由調(diào)用方指定,所以這個(gè)樣式
* 類名是一個(gè)組件屬性由外部傳入 */}
<Drag
handle={dragContorlClassName}
defaultClassName="js-drag-wrapped"
position={dragStartPosition as Point}
onStart={onDragStart}
onStop={onDragStop}
>
{/** 下面的div作為拖拽區(qū)域的外部容器 */}
<div style={{width:width}}>
<Resizable
style={{}}
onResize={onResize}
onResizeStop={onResizeStop}
minWidth={width}
defaultSize={{width: width,height:containerHeight}}
className={cx("js-resize-container popover-shadow",styles.resizeContainerShadow)}
>
{/** 下面的div用作Window的可見樣式,例如圓角
* 拖拽區(qū)域使用tansform圓角不起作用,背景色要透明
* 大小可變區(qū)域tansform圓角不起作用,背景色要透明
* 在可變區(qū)域增加div,設(shè)置圓角樣式,child有顏色,需要設(shè)置overflow:hidden
*/}
<div className={cx(styles.winPopover,styles.clearFix)}
ref={popoverRef}
onClick={e => {
e.stopPropagation();
}}
onDoubleClick={e => {
e.stopPropagation();
}}
>
{/** 承載外部設(shè)計(jì)組件
* 該實(shí)例只是展示了拖拽改變位置和大小,實(shí)際對(duì)外接口并不完善,需要根據(jù)自己的需求進(jìn)行擴(kuò)展
* 原則:外部組件不能直接改變一個(gè)組件的狀態(tài),所以組件內(nèi)公開能做什么事,由外部組件來通知,
* 內(nèi)部實(shí)際做具體的動(dòng)作。
*/}
{children}
</div>
</Resizable>
</div>
</Drag>
</div>
</>
);
}
export default DragableWindow;
代碼重點(diǎn),請(qǐng)參照代碼中的注釋,這樣描述更適合程序員來閱讀。
這里強(qiáng)調(diào)的一下,標(biāo)簽布局的層次,否則讀起來感覺一頭霧水。如下圖
布局容器層次
組件引用樣例
模擬了一個(gè)參照彈出窗口樣例(ReferWindow),見前面的視頻。樣例使用的是antd組件進(jìn)行布局演示
import React,{Component} from 'react'
import DragableWindow from './DragableWindow'
import {Button} from 'antd'
import {Flex,Layout} from 'antd'
import {CloseOutlined,WindowsOutlined} from '@ant-design/icons'
import {getUniqueString} from './utils'
const { Header, Sider,Footer } = Layout;
interface ReferWindowProps {
refType:string;
container:Element|DocumentFragment;
title?:string;
headIcon?:React.ReactNode;
headContents?:[React.ReactNode];
headComps?:[];
visible?:boolean;
children?:any;
closeListener?:(v:boolean) => void;
}
interface ReferWindowInnerProps {
visible?:boolean;
resizeHeight?:number;
max:boolean;
activeKey:number;
isExpandLeftArea:boolean;
isDragging:boolean;
}
class ReferWindow extends Component<ReferWindowProps,ReferWindowInnerProps>{
constructor(props:ReferWindowProps){
super(props);
this.state = {
visible:props.visible === undefined?true:props.visible,
max: false,
activeKey:0,
isExpandLeftArea:false,
isDragging:false
};
this.closeWindow.bind(this);
}
closeWindow = ()=>{
const {closeListener} = this.props;
closeListener&&closeListener(false);
}
render(): React.ReactNode {
const {title,headIcon} = this.props;
let winIcon = headIcon?headIcon:<WindowsOutlined/>;
let {visible} = this.props;
let uniqueString = getUniqueString();
return (
visible&&(
<DragableWindow height={360} width={600} dragContorlClassName={`.drag-header-${uniqueString}`}>
<Layout style={{height:'100%'}}>
<Header className={`drag-header-${uniqueString}`} style={{ cursor:'move', display: 'flex', alignItems: 'center',backgroundColor:'#f1f1f1', height:'50px', lineHeight:'50px',padding:'0px 15px' }}>
<Flex justify="space-between" align={'center'} style={{width:'100%',height:'100%'}} vertical={false}>
<Flex>{winIcon}<span style={{padding:'5px'}}>{title??title}</span></Flex>
<Flex align={'flex-end'}><CloseOutlined onClick={this.closeWindow} style={{cursor:'pointer'}}/></Flex>
</Flex>
</Header>
<Layout style={{}}>
<Sider width={200}>
</Sider>
</Layout>
<Footer style={{padding:'10px 10px'}}>
<Flex justify={'flex-end'}>
<span><Button type='primary'>確定</Button></span>
<span style={{padding:'0px 5px'}}><Button onClick={this.closeWindow}>取消</Button></span>
</Flex>
</Footer>
</Layout>
</DragableWindow>
))
};
}
export default ReferWindow;
參照
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import {Input} from 'antd';
import { BarsOutlined } from '@ant-design/icons';
import ReferWindow from './referWindow'
interface BaseReferProps {
refType:string;
container:Element|DocumentFragment;
title?:string;
}
interface BaseReferInnerProps {
popoverPanelVisible: boolean;
}
class BaseRefer extends Component<BaseReferProps,BaseReferInnerProps> {
constructor(props:BaseReferProps){
super(props);
this.state = {
popoverPanelVisible:false,
};
this.showPopoverPanel.bind(this)
this.onReferWindowCloseClick.bind(this);
}
showPopoverPanel = () => {
this.setState({popoverPanelVisible:true});
}
onReferWindowCloseClick = () =>{
this.setState({popoverPanelVisible:false});
}
render(): React.ReactNode {
const {container,refType,title} = this.props;
let { popoverPanelVisible } = this.state;
return <>
<Input addonAfter={<BarsOutlined style={{cursor:'pointer'}} onClick={this.showPopoverPanel.bind(this)}/>}></Input>
{ReactDOM.createPortal(
<ReferWindow
visible={popoverPanelVisible}
closeListener={this.onReferWindowCloseClick}
title={title}
refType={refType}
container={container}>
</ReferWindow>,
container
)}
</>
}
}
export default BaseRefer;
參照使用
import React from 'react';
import BaseRefer from './components/container/Refer/baseRefer'
import {Row,Col} from 'antd'
import './App.css';
const App : React.FC = () =>{
return (
<Row>
<Col span={6}><BaseRefer refType='treeGrid' title='門店商品' container={document.body}></BaseRefer></Col>
<Col span={18}></Col>
</Row>
)
}
export default App;
效果圖
學(xué)生就可以看懂的bootstrap基礎(chǔ)實(shí)戰(zhàn)系列,pre標(biāo)簽里是筆記總結(jié),動(dòng)手實(shí)際操作一下會(huì)加強(qiáng)理解。有疑問留言交流哦。
bootstrap是進(jìn)階html5很基礎(chǔ)常用的前端框架,可以做自適應(yīng)漂亮的界面,再堅(jiān)持一下,前端知識(shí)的大門就會(huì)打開了。
本節(jié)內(nèi)容有動(dòng)態(tài)顯示效果,建議實(shí)際操作一下。
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。