reactjs 各种变量调用

4,301 阅读8分钟

一、reactjs调用外部引入的js中的函数

  1. 函数挂在到全局变量上
    我们都知道javascript是有作用域的,我们将函数挂在到全局变量上就可以了。比如函数可以定义为全局函数。就可以使用了。 比如原来的函数为:
function sayHello(){
  alert("hello");
}

我们修改为

var sayHi = function sayHello(){
 alert("hello");
}

这样我们在reactj中

componentDidMount() {
  window.sayHi();
}

就可以调用了,同理将变量声明为全局变量的话,也可以在react中调用。 其实解决这个问题的核心关键就是作用域的问题。明白了这一点,问题迎刃而解。

二、react在一个组件中调用别的组件中的方法

  1. 先介绍一下要解决的问题:
  2. react中一个组件A和一个组件B,其中B是被connect(connect是redux中的方法)包装过的组件,包装成BContainer,A和BContainer的关系是兄弟关系,在同一个父元素下渲染。现在我们要在点击A的时候调用B中的方法
  3. 解决思路:主要是用到ref获取BContainer组件挂载之后的实例
render(){
    var b = null
    return(<BContainer ref={(node) => b = node}/>)
}
  1. ref中的回调函数会在组件被挂载之后执行,参数是组件的实例,所以这个时候变量b就是被挂载的组件B的实例。 这个实例对象是connect包装过后的方法,我们可以用
b.getWrappedInstance()
  1. 来获取到被包装的组件,但是注意记得在connect函数那里要加上参数{ withRef:true }才行
export default connect(
    mapStateToProps,
    mapDispatchToProps,
    null,
    { withRef: true }
)(B)

这样就可以获得B的实例了,就可以调用B中的方法了

  1. 要注意的,在B中定义方法时要这样定义
fun = ()=>{
}

这样相当于this.fun = ()=>{},
如果你像成员函数(比如constructor)那样定义:fun(){}它是会绑定在对象的原型(proto)上,因为constructor也是在原型上的

三、react 页面之间如何互相调用

  1. 首先在公共定义封装模块 也就是sources/scripts/components/marker/models.js 封装函数如下: 把函数封装到MarkerData下的一个属性addTextLayer,参数暴露参数别的页面就可以直接引用他下面的方法或者属性
//点击直观添加text标签的定义
let canvasText = document.createElement('canvas');
let ctxText = canvasText.getContext("2d");

MarkerData.addTextLayer=function(mapAir,mapAirData){
  AMap.plugin('AMap.CustomLayer', ()=>{
    //document.getElementsByTagName("body")[0].append(canvasText);
    let customLayer = new AMap.CustomLayer(canvasText, {
      zooms: [3, 10],
      alwaysRender:true,//缩放过程中是否重绘,复杂绘制建议设为false
      //bounds: map.getBounds(),
      zIndex: 8890
    });
    let onRender = () => {
      var size = this.map.getSize();//resize
      var width = size.width;
      var height = size.height;
      canvasText.style.width = width+'px'
      canvasText.style.height = height+'px'
      canvasText.width = width;
      canvasText.height = height;//清除画布
      ctxText.fillStyle = '#08f';
      ctxText.textAlign = 'center'
      console.log(ctxText);
      
      const station=this.map.stations;
      curAirTypes.
      console.log(station);
     
      const Obvious = document.getElementsByClassName('obvious')[0].getElementsByClassName('#switch-on')[0].classList[2];
      console.log(Obvious);	  
      let lnglatUin=[];
      for(let m of station){
        let lnglat = new AMap.LngLat(m.geo.lng, m.geo.lat);
        lnglatUin.push(lnglat);
      }
      if(Obvious) {
         for(let m of lnglatUin) {
          let pixel=this.map.lngLatToContainer(m);
          ctxText.fillText('2',pixel.x,pixel.y);
         }
      } else {
        
        for(let m of lnglatUin) {
          let pixel=this.map.lngLatToContainer(m);
          ctxText.clearRect(0,0,10000,10000); 
         }  
      }
    
    }
  })
}
  1. 暴露参数,就是在models.js下直接暴露
export default MarkerData;
  1. 公用封装函数直接导入marker.js ,
import MarkerData, { MarkerState, MarkerStyle, MarkerModel, MarkerDict } from './models';

并再同页面将他直接导出

export { MarkerData, MarkerState, MarkerStyle, MarkerModel, MarkerDict };
  • common.js下文件也是公共封装模块,位置在components的同级目录,scripts/common.js
export Marker, { MarkerData, MarkerState, MarkerStyle, MarkerModel, MarkerDict } from './components/map/marker/marker';
  1. 这样可以通过直接传递参数将他的方法传递出去,bridge.js页面将所有页面的参数都暴露出去,他的位置在sources/apps/aqmap/src/scripts/bridge.js 这个就是正常项目下的常规文件
export { Data, Cache, Permit, Map, Marker, MarkerData, MarkerState, MarkerStyle, MarkerModel, MarkerDict, SpatialGrids, SpatialLayer, WindLayer, Player } from '../../../../scripts/common';
  1. map.js引用该参数
import { Data, Cache, Map as CoreMap, Marker, MarkerData,addTextLayer, MarkerState, MarkerStyle, MarkerModel, MarkerDict, StationType, ProjectAreaLevel, MapDataSet, API, POSTDict, AirParams, ClassNameFormat, Project, Permission, Pinyin, Utils } from '../bridge';
  1. map.js调用该方法,并将当页面的值传递给addTextLayer 该函数
MarkerData.addTextLayer(map.air.source,mapAirData);

四、pubsub订阅传参

比如点击右侧的直观按钮,需要将状态发布出去,此处需要调用该事件,但是涉及到个问题,那就是调用该函数不能传参,所以必须得用事件订阅

MarkerData.addTextLayer();// 这样写没有参数传递是不可以的
PubSub.publish(MapToolBarModels.pubSubDict.mapLevelLockState.topic, { visiable: true });//这句代码也许不对,但是()中的2个参数是这样定义的

比如常规下开发目录下map,定义2个 参数,

const pubSubTopic="MapToolBar";
const pubSubDict={
  /**
   * 导航nav切换后触发
   * topic,{
		showLayerSwitch:false,
		showTrafficLayer:false,  //路况图层
    showWindLayer:false,  //风场动画图层
    showWeatherStations:false,//气象站
		showPollutantLayer:false,  //污染物图层
		showSatelliteLayer:false,  //卫星数据图层
	 }
   */
  moduleInitState:{token:null,topic:pubSubTopic+".moduleInitState"},  
  //左侧筛选器选择VOC站点后触发,函数输入值为(topic,{visiable:true,lock:true})
  mapLevelLockState:{token:null,topic:pubSubTopic+".mapLevelLockState"},
  //切换地图模式《-》数据分析模式触发,函数输入值为(topic,{isShow:true})
  showChange:{token:null,topic:pubSubTopic+".showChange"},
  airmapStationFilterChange:{token:null,topic:pubSubTopic+".PanelShowPollutantLayer"},
};

将这2个参数直接导出

export {pubSubDict,pubSubTopic};

后面可以直接用这2个参数的其他属性,比如

MapToolBarModels.pubSubDict.mapLevelLockState.topic

五、比如textlayer封装成单独的文件,直接可以调用

  1. 封装JS 文件包括
function TextLayer(map,amapCustomLayer,option) //定义
  1. 方法:
TextLayer.prototype.configure
TextLayer.prototype.initLayer =function(option){
//option就是传形参,这也是react中常用的方法,
    var canvasText= this.get("canvas");//直接获取到整体的数据
    let ctxText =canvasText.getContext("2d");   
    let map = this.get("map");
    let datas= this.get("data");
    this.get("amapLayer").render=function(){
        //这里只需要将数据传过来,具体数据的计算方法,在这里处理
    }
}
TextLayer.prototype.update 
TextLayer.prototype.update = function(data) {
	this.set("data",data);
	this.get("amapLayer").render();
}
TextLayer.prototype.dispose = function(data) {

}
  1. 调用它的页面比如nav-module-airmap页面
constructor()
//直观textlayertext图层
this.textLayer={
	ready : false, //是否初始化完毕
	layer : null,
	canvasText : null,
	layerOption : null,
	amapCustomLayer : null,
	data:[],
	isShow:false
}
  1. 初始化的时候:
//8:初始化直观textlayer
if(!this.textLayer.ready){
	let canvasText = document.createElement('canvas');
	canvasText.width = this.map.getSize().width;
	canvasText.height = this.map.getSize().height;
	canvasText.width = canvasText.width+'px'
    canvasText.height= canvasText.height+'px'

	this.textLayer.amapCustomLayer = new AMap.CustomLayer(canvasText, {
		zooms: [3, 18],
		zIndex: 889
	});
	this.textLayer.layerOption={
		canvas:canvasText,
		data:null
	};
	this.textLayer.layer=new TextLayer(this.map,this.textLayer.amapCustomLayer,this.textLayer.layerOption);
	this.textLayer.amapCustomLayer.setMap(this.map);
	this.textLayer.ready=true;
	}

然后在更新的地方加上代码:

//直观textlayer赋值历史数据
this.textLayer.data=datas;
if(this.textLayer.isShow){
    this.textLayer.amapCustomLayer.show();
    this.textLayer.layer.update(this.textLayer.data);
}
  1. pubsub订阅的时候调用这个函数
onToggleShowTextLayer(topic,opt){
	if(opt.isShow){
		this.textLayer.isShow=true;
		this.textLayer.amapCustomLayer.show();
		this.reqTextLayerToken=Moment().valueOf();
		this.textLayer.layer.update(this.textLayer.data);
		
	}
	else{
		this.textLayer.isShow=false;
		this.textLayer.amapCustomLayer.hide();
	}
  }

六、1》react中父组件调用子组件方法

//子组件 child.js

import react,{Component} from 'react'
export default class Child extends Component{
  constructor(props){
    super(props)
    this.state = { //声明变量
      text: '山有木兮木有枝' 
    }  
  }
  dream =(dat)=>{ //定义方法
    console.log('父组件调用子组件方法',dat)
  }
}
//父组件 parent.js

import react,{Component} from 'react'
import ChildPage from './child'

export default class Parent extends Component{
  fn(){
    this.refs.biaoji.dream('哈哈') //调用子组件的dream方法
  },
  render(){
    return(
        <div className="ParentBig">
          <div onClick={ this.fn }>点击</div>
          <ChildPage ref="biaoji"></ChildPage>
        </div>
    )
  }
}

六、2》react父组件调用子组件方法

基本思路:父组件可以通过props把自己的函数方法传递给子组件调用,那么子组件通过这个函数把自己的组件实例传回给父组件,父组件只需要保存这些实例便可以调用子组件的方法

父组件
import React, { Component } from 'react'
import {Layout } from 'antd'
import Friends from './friends'
import ChatWindow from "./chatWindow";
// 父组件
class Home extends Component{
    constructor (props) {
        super(props)
        this.state = { }
    }
    componentDidMount () {
    	// 等待子组件被挂载之后调用子组件方法
   		this.chatWindow.setChat ()
   		// 调用friends子组件中的方法
        this.friends.setFriends ()
    }
    // 获取子组件
    onRef (name, ref) {
        switch (name) {
            case 'chatWindow':
                this.chatWindow = ref
                break
            case 'friends':
                this.friends = ref
                break
            default:
                break
        }
    }
  
    render () {
        return(
            <Layout className='home'>
            // 好友列表子组件
                <Friends
                	 onRef={this.onRef.bind(this)}
                />
                // 聊天窗口子组件
                <ChatWindow
                            onRef={this.onRef.bind(this)}
                 />
            </Layout>
        )
    }
}
export default Home

子组件>friends子组件

import React, {Component} from 'react'

class friends extends Component{
    constructor (props) {
        super(props)
        this.state = {}
    }
    componentDidMount () {
    	// 调用父组件方法把当前实例传给父组件
        this.props.onRef('friends', this)
    }
    // 在父组件中调用的方法
    setFriends () {
        alert('子组件friends')
    }
    render () {
        return (
            <div className='friends'>friends</div>
        )
    }
}
export default friends

chatWindow子组件

import React, {Component} from 'react'

class chatWindow extends Component{
    constructor (props) {
        super(props)
        this.state = {}
    }
    componentDidMount () {
    	// 调用父组件方法把当前实例传给父组件
        this.props.onRef('chatWindow', this)
    }
    // 在父组件中调用的方法
    setFriends () {
        alert('子组件chatWindow')
    }
    render () {
        return (
            <div className='chatWindow'>chatWindow</div>
        )
    }
}
export default chatWindow

六、3》react中子组件调用父组件方法

整体思路:就是父组件的方法传给子组件,子组件通过传递参数,调用父组件的方法

父页面JS

render() {
    const { children } = this.props;
    return (
      <T_Analysis_PanelBody7
      onGetChildrenDom={this.getChildrenDom} //传递方法
       >
        { children }
      </T_Analysis_PanelBody7>
    }

父组件的方法调用

this.getChildrenDom(this.DOM.chartPunch);//chartPunchContainer相当于实参,必须赋值

父组件的方法定义

getChildrenDom(chartPunchContainer){
    this.DOM.chartPunch = chartPunchContainer;
}

子页面JSX

render() {
    const {onGetChildrenDom} = this.props;
    onGetChildrenDom(this.getDomChartPunchContainer());//传参给父页面
}

七、关于左侧点击切换显示AQI,

八、 同一个JS文件中一个对象引用另外一个对象里的方法

定义方法

const _Drawing = {
  // 圆弧
  newArc: function (ctx, center, eAngle = 2 * Math.PI, sAngle = 0, openPath = false,color) {
    let {x,y,radius} = center;
    ctx.beginPath();//本对象里引用地图的方法直接就可以用ctx
    ctx.arc(x, y, radius,sAngle, eAngle,openPath);
    if (!openPath) {
      ctx.closePath();
    }
    ctx.fillStyle = color;
    ctx.closePath();
    // 模糊和填充效果必须写到这里,否则不显示图标
    if(color !== '#aaa'){
      this.shadow(ctx, color, 0, 0, 20);
    }
    ctx.fill();
  }
 }

引用另外一个对象里的方法

const Marker = {
    pollution: function (gid) {
      const { state, color, eyestate } = gid;
      return function (ctx, x, y, width, height) {
        const bounds = Marker.getBounds(x, y, width, height);
        const { center } = bounds;
        x = center.x;
        y = center.y;
        let icoColor;

        // 判断在线离线设置颜色
        if( parseInt(state) === MarkerModel.STATE.ONLINE ) {
          icoColor = '#c79b56';
        }else if(parseInt(state) === MarkerModel.STATE.OFFLINE ){
          // _Drawing.fillStyle(ctx, "#aaa");
          icoColor = '#aaa';
        }

        // 烟雾的坐标
        const newArcs = {
          up:[{
            x: x-width/2,
            y: y-height/2,
            radius: width/4,
          },
          {
            x: x-width/4,
            y: y-height/5*2,
            radius: width/4,
          },
          {
            x: x+width/3,
            y: y-height/2,
            radius: width/3
          },
          {
            x: x+width/4*3,
            y: y-height/2,
            radius: width/4,
          }],

          down:[{
            x: x-width/4,
            y: y-height/5*3,
            radius: width/3,
          },
          {
            x: x-width/3,
            y: y-height/5*3,
            radius: width/3,
          },
          {
            x: x+width/4,
            y: y-height/3*2,
            radius: width/2
          },
          {
            x: x+width/3,
            y:y-height/5*3,
            radius: width/3,
          }],
        };
        const eAngle = 2 * Math.PI;
        const sAngle = 0;
        const openPath = false;

        // 烟雾
        for(const arc of newArcs.up){
          _Drawing.newArc(ctx, arc, eAngle, sAngle, openPath,icoColor);
        }
        for(const arc of newArcs.down){
          _Drawing.newArc(ctx, arc, eAngle, sAngle, openPath,icoColor);
        }

        // 烟筒 为_Drawing另外一个对象
        _Drawing.newRect(ctx,x-width/4*3,y,width/5,height/6*5,icoColor);//长
        _Drawing.newRect(ctx,x-width/10,y+height/6,width/5,height/3*2,icoColor);//短

        // 底部矩形
        _Drawing.newRect(ctx,x-width,y+height/4*3,width*3/2,height/6*3,icoColor);
        _Drawing.sanjiaoTh(ctx, x+width/2, y+height/4*3,width/2,height/6*3,icoColor);
        
        _Drawing.fill(ctx);
   
      }
}