--最近项目用react,学习react并使用cropper组件裁剪图片。

(这里开发组件不够统一有用tsx(TypeScript + xml/html)写的组件,有用jsx(javascript+xml/html)写的组件

前言:cropper组件引入到项目中的手顺直接看官方文档;github:https://github.com/fengyuanchen/cropperjs#methods  在线演示url: https://fengyuanchen.github.io/cropper/

1.cropper组件以及各种操作的简单封装。

  react-cropper.js文件

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Cropper from 'cropperjs'; const optionProps = [
'dragMode',
'aspectRatio',
'data',
'crop',
// unchangeable props start from here
'viewMode',
'preview',
'responsive',
'restore',
'checkCrossOrigin',
'checkOrientation',
'modal',
'guides',
'center',
'highlight',
'background',
'autoCrop',
'autoCropArea',
'movable',
'rotatable',
'scalable',
'zoomable',
'zoomOnTouch',
'zoomOnWheel',
'wheelZoomRatio',
'cropBoxMovable',
'cropBoxResizable',
'toggleDragModeOnDblclick',
'minContainerWidth',
'minContainerHeight',
'minCanvasWidth',
'minCanvasHeight',
'minCropBoxWidth',
'minCropBoxHeight',
'ready',
'cropstart',
'cropmove',
'cropend',
'zoom',
]; const unchangeableProps = optionProps; class ReactCropper extends Component {
componentDidMount() {
const options = Object.keys(this.props)
.filter(propKey => optionProps.indexOf(propKey) !== -1)
.reduce((prevOptions, propKey) =>
Object.assign({}, prevOptions, { [propKey]: this.props[propKey] }), {});
this.cropper = new Cropper(this.img, options); } UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.src !== this.props.src) {
this.cropper.reset().clear().replace(nextProps.src);
}
if (nextProps.aspectRatio !== this.props.aspectRatio) {
this.setAspectRatio(nextProps.aspectRatio);
}
if (nextProps.data !== this.props.data) {
this.setData(nextProps.data);
}
if (nextProps.dragMode !== this.props.dragMode) {
this.setDragMode(nextProps.dragMode);
}
if (nextProps.cropBoxData !== this.props.cropBoxData) {
this.setCropBoxData(nextProps.cropBoxData);
}
if (nextProps.canvasData !== this.props.canvasData) {
this.setCanvasData(nextProps.canvasData);
}
if (nextProps.moveTo !== this.props.moveTo) {
if (nextProps.moveTo.length > 1) {
this.moveTo(nextProps.moveTo[0], nextProps.moveTo[1]);
} else {
this.moveTo(nextProps.moveTo[0]);
}
}
if (nextProps.zoomTo !== this.props.zoomTo) {
this.zoomTo(nextProps.zoomTo);
}
if (nextProps.rotateTo !== this.props.rotateTo) {
this.rotateTo(nextProps.rotateTo);
}
if (nextProps.scaleX !== this.props.scaleX) {
this.scaleX(nextProps.scaleX);
}
if (nextProps.scaleY !== this.props.scaleY) {
this.scaleY(nextProps.scaleY);
}
if (nextProps.enable !== this.props.enable) {
if (nextProps.enable) {
this.enable();
} else {
this.disable();
}
} Object.keys(nextProps).forEach((propKey) => {
let isDifferentVal = nextProps[propKey] !== this.props[propKey];
const isUnchangeableProps = unchangeableProps.indexOf(propKey) !== -1; if (typeof nextProps[propKey] === 'function' && typeof this.props[propKey] === 'function') {
isDifferentVal = nextProps[propKey].toString() !== this.props[propKey].toString();
} if (isDifferentVal && isUnchangeableProps) {
throw new Error(`prop: ${propKey} can't be change after componentDidMount`);
}
});
} componentWillUnmount() {
if (this.img) {
// Destroy the cropper, this makes sure events such as resize are cleaned up and do not leak
this.cropper.destroy();
delete this.img;
delete this.cropper;
}
} setDragMode(mode) {
return this.cropper.setDragMode(mode);
} setAspectRatio(aspectRatio) {
return this.cropper.setAspectRatio(aspectRatio);
} getCroppedCanvas(options) {
return this.cropper.getCroppedCanvas(options);
} setCropBoxData(data) {
return this.cropper.setCropBoxData(data);
} getCropBoxData() {
return this.cropper.getCropBoxData();
} setCanvasData(data) {
return this.cropper.setCanvasData(data);
} getCanvasData() {
return this.cropper.getCanvasData();
} getImageData() {
return this.cropper.getImageData();
} getContainerData() {
return this.cropper.getContainerData();
} setData(data) {
return this.cropper.setData(data);
} getData(rounded) {
return this.cropper.getData(rounded);
} crop() {
return this.cropper.crop();
} move(offsetX, offsetY) {
return this.cropper.move(offsetX, offsetY);
} moveTo(x, y) {
return this.cropper.moveTo(x, y);
} zoom(ratio) {
return this.cropper.zoom(ratio);
} zoomTo(ratio) {
return this.cropper.zoomTo(ratio);
} rotate(degree) {
return this.cropper.rotate(degree);
} rotateTo(degree) {
return this.cropper.rotateTo(degree);
} enable() {
return this.cropper.enable();
} disable() {
return this.cropper.disable();
} reset() {
return this.cropper.reset();
} clear() {
return this.cropper.clear();
} replace(url, onlyColorChanged) {
return this.cropper.replace(url, onlyColorChanged);
} scale(scaleX, scaleY) {
return this.cropper.scale(scaleX, scaleY);
} scaleX(scaleX) {
return this.cropper.scaleX(scaleX);
} scaleY(scaleY) {
return this.cropper.scaleY(scaleY);
} render() {
const {
src,
alt,
crossOrigin,
style,
className,
} = this.props; return (
<div
style={style}
className={className}
>
<img
crossOrigin={crossOrigin}
ref={(img) => { this.img = img; }}
src={src}
alt={alt === undefined ? 'picture' : alt}
style={{ opacity: 0 }}
/>
</div>
);
}
} ReactCropper.propTypes = {
style: PropTypes.object, // eslint-disable-line react/forbid-prop-types
className: PropTypes.string, // react cropper options
crossOrigin: PropTypes.string,
src: PropTypes.string,
alt: PropTypes.string, // props of option can be changed after componentDidmount
aspectRatio: PropTypes.number,
dragMode: PropTypes.oneOf(['crop', 'move', 'none']),
data: PropTypes.shape({
x: PropTypes.number,
y: PropTypes.number,
width: PropTypes.number,
height: PropTypes.number,
rotate: PropTypes.number,
scaleX: PropTypes.number,
scaleY: PropTypes.number,
}),
scaleX: PropTypes.number,
scaleY: PropTypes.number,
enable: PropTypes.bool,
cropBoxData: PropTypes.shape({
left: PropTypes.number,
top: PropTypes.number,
width: PropTypes.number,
height: PropTypes.number,
}),
canvasData: PropTypes.shape({
left: PropTypes.number,
top: PropTypes.number,
width: PropTypes.number,
height: PropTypes.number,
}),
zoomTo: PropTypes.number,
moveTo: PropTypes.arrayOf(PropTypes.number),
rotateTo: PropTypes.number, // cropperjs options
// https://github.com/fengyuanchen/cropperjs#options
// aspectRatio, dragMode, data
viewMode: PropTypes.oneOf([0, 1, 2, 3]),
preview: PropTypes.string,
responsive: PropTypes.bool,
restore: PropTypes.bool,
checkCrossOrigin: PropTypes.bool,
checkOrientation: PropTypes.bool,
modal: PropTypes.bool,
guides: PropTypes.bool,
center: PropTypes.bool,
highlight: PropTypes.bool,
background: PropTypes.bool,
autoCrop: PropTypes.bool,
autoCropArea: PropTypes.number,
movable: PropTypes.bool,
rotatable: PropTypes.bool,
scalable: PropTypes.bool,
zoomable: PropTypes.bool,
zoomOnTouch: PropTypes.bool,
zoomOnWheel: PropTypes.bool,
wheelZoomRatio: PropTypes.number,
cropBoxMovable: PropTypes.bool,
cropBoxResizable: PropTypes.bool,
toggleDragModeOnDblclick: PropTypes.bool,
minContainerWidth: PropTypes.number,
minContainerHeight: PropTypes.number,
minCanvasWidth: PropTypes.number,
minCanvasHeight: PropTypes.number,
minCropBoxWidth: PropTypes.number,
minCropBoxHeight: PropTypes.number,
ready: PropTypes.func,
cropstart: PropTypes.func,
cropmove: PropTypes.func,
cropend: PropTypes.func,
crop: PropTypes.func,
zoom: PropTypes.func,
}; ReactCropper.defaultProps = {
src: null,
dragMode: 'crop',
data: null,
scaleX: 1,
scaleY: 1,
enable: true,
zoomTo: 1,
rotateTo: 0,
}; export default ReactCropper;

2.cropper组件调用的简单封装

CropperView.jsx文件

import React, { Component, useEffect } from 'react';
import $ from "jquery";
import Cropper from './cropper/react-cropper'
import 'cropperjs/dist/cropper.css' /* global FileReader */
var showCropArea = true; export default class CropperView extends Component { constructor(props) {
super(props);
this.state = {
cropResult: null,
};
// this.cropper = this;
this.onChange = this.onChange.bind(this);
this.src = props.src;
} // componentDidMount(){
// useEffect(() => {
// alert("cropZone" + this.cropper);
// // if (typeof this.cropper.getCroppedCanvas() === 'undefined') {
// // return;
// // }
// alert("left:" + this.cropper.getCropBoxData().left
// + "top:" + this.cropper.getCropBoxData().top
// + "width:" + this.cropper.getCropBoxData().width
// + "height:" + this.cropper.getCropBoxData().height);
// }, [this.props.save]);
// } onChange(e) {
e.preventDefault();
let files;
if (e.dataTransfer) {
files = e.dataTransfer.files;
} else if (e.target) {
files = e.target.files;
}
const reader = new FileReader();
reader.onload = () => {
this.setState({ src: reader.result });
};
reader.readAsDataURL(files[0]);
} cropZone() {
if (typeof this.cropper.getCroppedCanvas() === 'undefined') {
return;
}
alert("left:" + this.cropper.getCropBoxData().left
+ "top:" + this.cropper.getCropBoxData().top
+ "width:" + this.cropper.getCropBoxData().width
+ "height:" + this.cropper.getCropBoxData().height);
$(".cropper-crop-box").hide();
$(".cropper-drag-box").hide();
$(".cropper-wrap-box").append(
"<div style=\"width:" + this.cropper.getCropBoxData().width + ";"
+ "height:" + this.cropper.getCropBoxData().height + ";"
+ "background:#0000FF; opacity:0.3"
+ "position:absolute; left:" + this.cropper.getCropBoxData().left +";"
+ "top:" + this.cropper.getCropBoxData().top + ";\">");
} showCropZone() {
if (showCropArea) {
$(".cropper-crop-box").css("display", "block");
$(".cropper-drag-box").css("display", "block");
} else {
$(".cropper-crop-box").hide();
$(".cropper-drag-box").hide();
}
} creatCrop(){
this.cropper.crop();
} clearCrop(){
this.cropper.clear();
} resetCrop(){
this.cropper.reset();
} moveLeft(){
this.cropper.move(-5, 0);
} moveRight(){
this.cropper.move(5, 0);
} moveUp(){
console.log("====moveUp===");
try {
this.cropper.move(0, -5);
}catch (err){
console.log(err);
}
} moveDown(){
this.cropper.move(0, 5);
} enlarge(){
try {
// 放大
// this.cropper.zoom(0.1);
var allCanvasDate = this.cropper.getCanvasData();
var newCanvasDate = {left:allCanvasDate.left, top: allCanvasDate.top,
width: allCanvasDate.width*2, height: allCanvasDate.height*2} this.cropper.setCanvasData(newCanvasDate); }catch (err){
console.log(err);
} } shrink(){
try {
// 缩小
// this.cropper.zoom(-0.1)
var allCanvasDate = this.cropper.getCanvasData();
var newCanvasDate = {left:allCanvasDate.left, top: allCanvasDate.top,
width: allCanvasDate.width*0.5, height: allCanvasDate.height*0.5} this.cropper.setCanvasData(newCanvasDate);
}catch (err){
console.log(err);
}
} test(){
try {
var allDate = this.cropper.getData(true);
alert(allDate.toString());
var par = {x:allDate.x, y:allDate.y, width:allDate.width*2, height:allDate.height*2,
rotate:allDate.rotate, scaleX:allDate.scaleX, scaleY:allDate.scaleY} this.cropper.setData(par);
}catch (err){
console.log(err);
}
} moveCrop(){
//this.cropper.movecrop();
console.log("===move===crop===");
} reduceCrop(){
var par = {left:this.cropper.getCropBoxData().left, top:this.cropper.getCropBoxData().top,
width:this.cropper.getCropBoxData().width*0.8, height:this.cropper.getCropBoxData().height*0.8}
this.cropper.setCropBoxData(par);
} raiseCrop(){
var par = {left:this.cropper.getCropBoxData().left, top:this.cropper.getCropBoxData().top,
width:this.cropper.getCropBoxData().width*1.2, height:this.cropper.getCropBoxData().height*1.2}
this.cropper.setCropBoxData(par);
} CropLeft(){
var par = {left:this.cropper.getCropBoxData().left - 10, top:this.cropper.getCropBoxData().top,
width:this.cropper.getCropBoxData().width, height:this.cropper.getCropBoxData().height}
this.cropper.setCropBoxData(par);
} CropRight(){
var par = {left:this.cropper.getCropBoxData().left + 10, top:this.cropper.getCropBoxData().top,
width:this.cropper.getCropBoxData().width, height:this.cropper.getCropBoxData().height}
this.cropper.setCropBoxData(par);
} CropUp(){
var par = {left:this.cropper.getCropBoxData().left, top:this.cropper.getCropBoxData().top - 10,
width:this.cropper.getCropBoxData().width, height:this.cropper.getCropBoxData().height}
this.cropper.setCropBoxData(par);
} CropDown(){
var par = {left:this.cropper.getCropBoxData().left, top:this.cropper.getCropBoxData().top + 10,
width:this.cropper.getCropBoxData().width, height:this.cropper.getCropBoxData().height}
this.cropper.setCropBoxData(par);
} render() {
return (
<div className="r-view" style={{ position:'absolute', left:'185px', top:"83px" }}>
<Cropper
style={{ height:'100%', width:'auto' }}
aspectRatio={16 / 9}
preview=".img-preview"
guides={false}
src={this.props.src}
viewMode={2}
minContainerWidth={585}
minContainerHeight={430}
ref={cropper => { this.cropper = cropper; }}
zoomable={true}
zoomOnTouch={true}
/>
</div>
);
}
}

3.cropper组件与各种按钮操作的绑定(原因:设备上不会支持手指在选择区域的操作以及图片的放大缩小操作),页面整合组件。

  CropperScreen.tsx文件

import * as React from 'react';
import styled from "styled-components";
import useTranslate from "../../hooks/useTranslate";
import CropView from "./CropperView";
import 'cropperjs/dist/cropper.css' import FormView from "./FormView" const AppStyle = styled.div`
background: #CCC;
`; var showCropArea = false; export default function CropperScreen() {
const t = useTranslate(); const handleBackClicked = () => {
$("#viewable").show();
$("#scan_settings_id").css("display","none");
}; const doCropClicked = () => {
// showCropArea = !showCropArea;
// if (showCropArea) {
// alert("disabled false");
// $("#btn_save_crop").removeAttr("disabled");
// } else {
// alert("disabled true");
// $("#btn_save_crop").attr("disabled", "true");
// }
// cropUser.showCropZone(showCropArea); cropUser.clearCrop(); }; const doSaveCropClicked = () => {
cropUser.cropZone();
}; const handReset = () => {
cropUser.resetCrop();
cropUser.creatCrop();
} const handMoveLeft = () => {
cropUser.moveLeft();
} const handMoveRight = () => {
cropUser.moveRight();
} const handMoveUp = () => {
console.log("====handMoveUp===");
try {
cropUser.moveUp();
}catch (err){
console.log(err);
}
} const handMoveDown = () => {
cropUser.moveDown();
} const handMoveCrop = () => {
alert("unknow");
cropUser.moveCrop();
} const handReduceCrop = () => {
cropUser.reduceCrop();
} const handRaiseCrop = () => {
cropUser.raiseCrop()
} const handEnlarge = () => {
cropUser.enlarge();
} const handShrink = () => {
cropUser.shrink();
} const handCropLeft = () => {
cropUser.CropLeft()
} const handCropRight = () => {
cropUser.CropRight()
} const handCropUp = () => {
cropUser.CropUp()
} const handCropDown = () => {
cropUser.CropDown()
} const handTest = () => {
cropUser.test()
} const handleSubmit = () => {
alert("====handleSubmit====");
console.log(formUser); console.log(formUser.state);
} let maxItem = 2;
let cropUser
let formUser
var initValue = {name:'tom',job: '12'} return (
<AppStyle id="scan_settings_id" className="r-view" style={{display:"none", height:"470px"}}>
<header className="r-titlebar">
<a href="#" className="r-titlebar__back" onClick={handleBackClicked} />
<h1 className="r-titlebar__title">Preview</h1>
</header>
<div style={{position:"absolute", left:35}}>
</div>
<CropView ref={cropView => {cropUser = cropView}} src={require('../smartsdk-css/img/test.png')}/>
<div className="r-floating-island">
<div>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={doCropClicked}>Crop</button>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={doSaveCropClicked}>Save</button>
</div>
<div>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={handReset}>reset</button>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={handMoveCrop}>mcrop</button>
</div>
<div>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={handMoveLeft}>left</button>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={handMoveRight}>right</button>
</div>
<div>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={handMoveUp}>up</button>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={handMoveDown}>down</button>
</div>
<div>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={ handEnlarge}>+</button>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={ handShrink}>-</button>
</div>
<div>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={ handReduceCrop}>reduce</button>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={ handRaiseCrop}>raise</button>
</div> <div>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={ handCropLeft}>cropr</button>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={ handCropRight}>cropl</button>
</div> <div>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={ handCropUp}>cropu</button>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={ handCropDown}>cropd</button>
</div>
<div>
<button style={{width:'70px', height:'35px', marginLeft:'5px'}} onClick={ handTest}>test</button>
</div> {/* <FormView handleSubmit={handleSubmit} ref={formView => {formUser = formView}} props = {initValue}/> */} {/* <button className="r-start-button">
{t("dapi:cba.common.start")}
</button> */}
</div>
</AppStyle >
);
}

4.最后调用整体的组件,页面展示

页面

react中使用截图组件Cropper组件的更多相关文章

  1. React中的Context——从父组件传递数据

    简介:在React中,数据可以以流的形式自上而下的传递,每当你使用一个组件的时候,你可以看到组件的props属性会自上而下的传递.但是,在某些情况下,我们不想通过父组件的props属性一级一级的往下传 ...

  2. react 中的无状态函数式组件

    无状态函数式组件,顾名思义,无状态,也就是你无法使用State,也无法使用组件的生命周期方法,这就决定了函数组件都是展示性组件,接收Props,渲染DOM,而不关注其他逻辑. 其实无状态函数式组件也是 ...

  3. 基于 React 实现一个 Transition 过渡动画组件

    过渡动画使 UI 更富有表现力并且易于使用.如何使用 React 快速的实现一个 Transition 过渡动画组件? 基本实现 实现一个基础的 CSS 过渡动画组件,通过切换 CSS 样式实现简单的 ...

  4. 理解React中es6方法创建组件的this

    首发于:https://mingjiezhang.github.io/(转载请说明此出处). 在JavaScript中,this对象是运行时基于函数的执行环境(也就是上下文)绑定的. 从react中的 ...

  5. React中父组件与子组件之间的数据传递和标准化的思考

    React中父组件与子组件之间的数据传递的的实现大家都可以轻易做到,但对比很多人的实现方法,总是会有或多或少的差异.在一个团队中,这种实现的差异体现了每个人各自的理解的不同,但是反过来思考,一个团队用 ...

  6. React 深入系列1:React 中的元素、组件、实例和节点

    文:徐超,<React进阶之路>作者 授权发布,转载请注明作者及出处 React 深入系列,深入讲解了React中的重点概念.特性和模式等,旨在帮助大家加深对React的理解,以及在项目中 ...

  7. [转] React 中组件间通信的几种方式

    在使用 React 的过程中,不可避免的需要组件间进行消息传递(通信),组件间通信大体有下面几种情况: 父组件向子组件通信 子组件向父组件通信 跨级组件之间通信 非嵌套组件间通信 下面依次说下这几种通 ...

  8. react中直接调用子组件的方法(非props方式)

    我们都知道在 react中,若要在父组件调用子组件的方法,通常我们会采用在父组件定义一个方法,作为props转给子组件,然后执行该方法,可以获取到子组件传回的参数以得到我们的目的. 显而易见,这个执行 ...

  9. React 中的 Component、PureComponent、无状态组件 之间的比较

    React 中的 Component.PureComponent.无状态组件之间的比较 table th:first-of-type { width: 150px; } 组件类型 说明 React.c ...

随机推荐

  1. 申请免费的ssl通配符证书

    吐曹: 为了给我网站配置免费的htpps证书费死劲了, 折腾了一天, 找阿里阿里给我反馈的和我自己看的一样, 没什么用 我用Certbot生成证书以后怎么访问都是阿里的免费的hppts证书, 我都把阿 ...

  2. Solution -「SP 6779」GSS7

    \(\mathcal{Description}\)   给定一棵 \(n\) 个点的带点权树,\(q\) 次操作: 路径点权赋值. 询问路径最大子段和(可以为空).   \(n,q\le10^5\). ...

  3. MYSQL 获取最近多少天时间列表

    1.首先获取一个最近1000天的时间列表,如果不够可以按规则再加 SELECT adddate(CURDATE(),-(t2.i * 100 + t1.i * 10 + t0.i)) date FRO ...

  4. BI工具有多重要?凭什么得到各类企业的热烈追捧?

    近年来,应用BI工具的企业越来越多,企业对BI工具的重视说明企业了解.认识到了数据的价值.数据分析工具已经渐渐成为企业日常经营管理活动中不可或缺的一项重要工作内容.但是你知道企业应该如何挑选BI工具吗 ...

  5. 【基础概念】匹夫细说C#:不是“栈类型”的值类型,从生命周期聊存储位置

    转载地址 https://www.cnblogs.com/murongxiaopifu/p/4419040.html 0x00 前言: 匹夫在日常和别人交流的时候,常常会发现一旦讨论涉及到" ...

  6. Linux Shell脚本_关闭防火墙

    转至:https://blog.csdn.net/weixin_40816738/article/details/105244851 ① 脚本编写创建脚本 vim closeFirewall.sh 添 ...

  7. 深入Mybatis框架

    深入Mybatis框架 学习了Spring之后,我们已经了解如何将一个类作为Bean交由IoC容器管理,也就是说,现在我们可以通过更方便的方式来使用Mybatis框架,我们可以直接把SqlSessio ...

  8. python+pytest(3)-接口测试一般流程及方法

    首先我们要明确,通常所接口测试其实就属于功能测试,主要校验接口是否实现预定的功能,虽然有些情况下可能还需要对接口进行性能测试.安全性测试. 在学习接口自动化测试之前,我们先来了解手工接口测试怎样进行. ...

  9. IIS部署vue项目页面刷新404,url重写问题解决办法

    这里需要用到URL重写工具 --URL Rewrite(默认没有,需要自己下载安装) 如果IIS上默认有安装Web平台安装程序,我们可以使用平台自动安装URL Rewrite重写工具,打开IIS在管理 ...

  10. shell 和python 实现ftp文件上传或者下载

    一.shell脚本 #####从ftp服务器上的/home/data 到 本地的/home/databackup#####!/bin/bashftp -n<<!open 172.168.1 ...