一、reactjs调用外部引入的js中的函数
- 函数挂在到全局变量上
我们都知道javascript是有作用域的,我们将函数挂在到全局变量上就可以了。比如函数可以定义为全局函数。就可以使用了。 比如原来的函数为:
function sayHello(){
alert("hello");
}
我们修改为
var sayHi = function sayHello(){
alert("hello");
}
这样我们在reactj中
componentDidMount() {
window.sayHi();
}
就可以调用了,同理将变量声明为全局变量的话,也可以在react中调用。 其实解决这个问题的核心关键就是作用域的问题。明白了这一点,问题迎刃而解。
二、react在一个组件中调用别的组件中的方法
- 先介绍一下要解决的问题:
- react中一个组件A和一个组件B,其中B是被connect(connect是redux中的方法)包装过的组件,包装成BContainer,A和BContainer的关系是兄弟关系,在同一个父元素下渲染。现在我们要在点击A的时候调用B中的方法
- 解决思路:主要是用到ref获取BContainer组件挂载之后的实例
render(){
var b = null
return(<BContainer ref={(node) => b = node}/>)
}
- ref中的回调函数会在组件被挂载之后执行,参数是组件的实例,所以这个时候变量b就是被挂载的组件B的实例。 这个实例对象是connect包装过后的方法,我们可以用
b.getWrappedInstance()
- 来获取到被包装的组件,但是注意记得在connect函数那里要加上参数{ withRef:true }才行
export default connect(
mapStateToProps,
mapDispatchToProps,
null,
{ withRef: true }
)(B)
这样就可以获得B的实例了,就可以调用B中的方法了
- 要注意的,在B中定义方法时要这样定义
fun = ()=>{
}
这样相当于this.fun = ()=>{},
如果你像成员函数(比如constructor)那样定义:fun(){}它是会绑定在对象的原型(proto)上,因为constructor也是在原型上的
三、react 页面之间如何互相调用
- 首先在公共定义封装模块 也就是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);
}
}
}
})
}
- 暴露参数,就是在models.js下直接暴露
export default MarkerData;
- 公用封装函数直接导入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';
- 这样可以通过直接传递参数将他的方法传递出去,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';
- 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';
- 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封装成单独的文件,直接可以调用
- 封装JS 文件包括
function TextLayer(map,amapCustomLayer,option) //定义
- 方法:
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) {
}
- 调用它的页面比如nav-module-airmap页面
constructor()
//直观textlayertext图层
this.textLayer={
ready : false, //是否初始化完毕
layer : null,
canvasText : null,
layerOption : null,
amapCustomLayer : null,
data:[],
isShow:false
}
- 初始化的时候:
//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);
}
- 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);
}
}