其实这里有点标题党的嫌疑,其实这个项目在一月初的时间已经完成了,因为是 webAr 项目的初始应用(没有使用打包工具和 cli ),加上业务逻辑很复杂,所以这里实际上是基于 Vue-li下对于项目的总结

错误 : Class constructor FunName cannot be invoked without 'new'

  • 起由:直接调用的父类的时候无法使用子类继承,只能通过 new 的方式,即: 无法使用已转换的类扩展本机类
  • 方法:修改.babelrc - 排除 transform-es2015-classes
// <!-- 参考:https://stackoverflow.com/questions/36577683/babel-error-class-constructor-foo-cannot-be-invoked-without-new -->
presets: [
    ["env", {
        exclude: ["transform-es2015-classes"]
    }]
]

功能 : 添加 css2DLabel 进行场景的特殊标注

  • 起由: 添加 css2Dcanvas 无法使用定义好的事件;
  • 方法:修改 css2Dz-index ,并需要传递已定义的事件
is_render = true;

//初始化css2DRender && Dom style
let css2DRender = new THREE.CSS2DRenderer(viewer);
initCSS2DRender(css2DRenderer);

// 赋值事件,添加Dom
css2DRender.domElement.ondbclick = () => {
    terrain.methods.dbFinishToolEvents
};
css2DRender.domElement.onclick = () => {
    terrain.methods.FinishToolEvents
};
document.getElementById("container").appendChild(css2DRenderer.domElement);

// 场景更新
viewer.onEndRenderTechnique = () => {
    if (is_render) {
        css2DRenderer.render(scene, camera)
    }
}

关于 css2DLabelLayeraddLabel 方法的改写:

通过 imgconfig 参数配置的传递生成 ImgIcon 部分

// dom 添加 imgIcon
labelDiv.appendChild(getCSS2DIcon(imgconfig));

/**
 * 生成 ImgIcon
 * @param {Object} config - 用于生成 ImgIcon 的配置
 * @returns Image Dom
 */
function getCSS2DIcon(config) {
  let CSS2D_IMGCONFIG;
  config ? CSS2D_IMGCONFIG = config : CSS2D_IMGCONFIG = {
    src: '/static/img/position.gif',
    width: "30px",
    height: "40px",
    position: "absolute",
    top: "24px",
    left: "32%"
  };

  let imgIcon = new Image();
  imgIcon.src = CSS2D_IMGCONFIG.src;
  Object.assign(imgIcon.style, CSS2D_IMGCONFIG);

  return imgIcon;
}
//在创建css2DLayer的时:利用 dom 生成 cssLabel
let cssLabel = new THREE.CSS2DObject(labelDiv);
cssLabel.heightRatio = 5; // 设定 heightRatio (4-使用gif中心为旋转的点)
this.add(cssLabel);  //此处的this是 CSS2DLabelLayer 类

功能:在对canvas上进行事件监听的用于满足逻辑(通常是工具类的自动关闭)

//Html Dom
// <canvas id="canvasView" @click="finishToolsEvent" @dblclick="dbFinishToolsEvent"></canvas>

//JS methods
finishToolsEvent(timeout = 300){
  if(this.clickTimer){
      window.clearTimeout(this.clickTimer);
      this.clickTimer = null;
  }

  this.clickTimer = window.setTimeOut(() => {
    // do something single click
  },timeout)
},
dbFinishToolsEvent(){
	if (this.clickTimer) {
    window.clearTimeout(this.clickTimer);
      this.clickTimer = null;
  }
  //do something dbclick
}

功能 : 对于一些加载时间比较久的组件,不希望功能切换的时候状态丢失;

  • 方法:使用vue-routerkeep-alive 保持加载完成的状态;
//vue component
<keep-alive>
     <router-view v-if='$router.meta.keep_alive'></router-view>
</keep-alive>
<router-view v-if='!$router.meta.keep_alive'></router-view>
// router/index.js
export default new Router({
    route: [{
        // ....   
        children: [{
            path: './SatelliteImgContrast',
            component: resolve => require(['@components/satelliteImgContrast'], resolve),
            meta: {
                title: 'xx',
                keep_alive: true
            }
        }]
    }]
})

基于 Vuex 的数据管理

由于迁移了较多的功能,整个项目数据状态较多,使用了Vuex进行数据管理;

storeVue-cli的组织结构如下

├── index.html
├── main.js
├── components
└── store
    ├── index.js          #  组装模块并导出 store
    ├── state.js          #  state (存储状态)
    ├── getters.js        #  getter (派生状态)
    ├── mutation-types.js #  constant (状态修改类型)
    ├── mutations.js      #  mutation (提交状态修改)
    ├── actions.js        #  action (异步操作 - 提交mutation)

可以提及一下的是:

  • mutation-type.js 是单独存放 mutation 的类型存在的,和 mutation 配合使用的

Example:

// mutation-type.js
export const SET_ALLLAYER_DATA = "SET_ALLLAYER_DATA";
export const DEL_DREWLAYER_DATA = "DEL_DREWLAYER_DATA";

// mutation.js
import * as types from './mutation-type.js';

export default {
    [types.SET_ALLLAYER_DATA](state, {name, data}) {
        state.layerData[name] = data;
    },
    [types.DEL_DREWLAYER_DATA](state, uuid) {
        state.layerData.forEach((ele, i, arr) => {
            if (ele.uuid === uuid) arr.splice(index, 1)
        })
    }
}

  • action 提供异步操作,并提交 mutation

action 第一个参数默认是和 store 具有相同参数属性的对象。实际上 action 不具有修改 state 的能力,依旧通过提交(触发)mutation 实现修改;

// store.dispatch(actionType)
// action.js
import * as types from './mutation-type.js';

export default {
  actionExample({ commit }, { uuid, name, data }) {
    commit(types.DEL_DREWLAYER_DATA, uuid);
    commit({ type: types.SET_ALLLAYER_DATA, name, data });
  }
};
  • 辅助函数 mapState/mapGetters/mapMutations/mapActions

当需要在组件中引用的方法或者属性较多的时候我们使用辅助函数帮助我们实现, 对象展开运算符把我们需要的属性和方法映射到到对应的父级(vue属性);

// 几种不同的方式
import {mapGetters, mapMutations, mapActions} from 'vuex';
export default {
    computed: {
        ...mapGetters(['getLayerData','getDrawLayerData']),//名称与 state 的子节点名称相同时
        ...mapState({
          excavateData: state => state.excavate.data
        })
    },
    methods: {
        ...mapMutations({
            setData: 'SET_ALLLAYER_DATA',//另取一个名字,使用对象形式
            deleteDrawData: 'DEL_DREWLAYER_DATA'
        }),
        ...mapActions([ actionExample ])
    }
};