vueプロジェクト先端知識点整理【コレクション】

13311 ワード

WeChatライセンスは、ブラウザの戻るキーでライセンスページに戻ることもできます.
ナビゲーションガードではnext({})にreplace:trueを設定してルート変更、routerにリダイレクトすることができる.义齿

router.beforeEach((to, from, next) => {
 if (getToken()) {
 ...
 } else {
 //        ,      
 setUrl(to.fullPath)
 next({ path: '/author', replace: true })
 }
})

ルート切り替え時にページが自動的に上部に戻らない

const router = new VueRouter({
 routes: [...],
 scrollBehavior (to, from, savedPosition) {
 return new Promise((resolve, reject) => {
  setTimeout(() => {
  resolve({ x: 0, y: 0 })
  }, 0)
 })
 }
})

iosシステムは、微信ブラウザinputがフォーカスを失った後、ページが自動的にバウンドしません.
初期の解決策はinput上でonblurイベントをバインドすることであり、欠点は複数回バインドすることであり、第三者コンポーネントに存在し、イベントをバインドできないinputもある.
その後の解決策はfocusinイベントをグローバルにバインドすることであり,focusinイベントはバブルを起こし,最外層のbodyに捕獲されるからである.

util.wxNoScroll = function() {
 let myFunction
 let isWXAndIos = isWeiXinAndIos()
 if (isWXAndIos) {
  document.body.addEventListener('focusin', () => {
   clearTimeout(myFunction)
  })
  document.body.addEventListener('focusout', () => {
   clearTimeout(myFunction)
   myFunction = setTimeout(function() {
    window.scrollTo({top: 0, left: 0, behavior: 'smooth'})
   }, 200)
  })
 }
 
 function isWeiXinAndIos () {
  let ua = '' + window.navigator.userAgent.toLowerCase()
  let isWeixin = /MicroMessenger/i.test(ua)
  let isIos = /\(i[^;]+;( U;)? CPU.+Mac OS X/i.test(ua)
  return isWeixin && isIos
 }
}

子コンポーネントで親コンポーネントが渡す値を変更するとエラーが表示されます.
vueのpropsは一方向にバインドされていますが、propsのタイプが配列またはオブジェクトの場合、サブコンポーネント内でpropsの値コンソールを変更しても警告されません.配列またはオブジェクトはアドレス参照であるため、政府はサブコンポーネント内で親コンポーネントの値を変更することを提案していません.これはvueにおけるpropsの一方向バインドの考え方に違反します.したがってprops値を変更する際に$emitを使用する必要があり、より簡単な方法は使用することである.sync修飾子.

//      
this.$emit('update:title', newTitle)
//     
    JS-SDK         

まずwxを呼び出す.chooseImage()は、ユーザーを導いて写真を撮ったり、携帯電話のアルバムから図を選んだりします.画像のlocalIdが正常に取得され、wxが呼び出されます.uploadImage()は、ローカルピクチャを微信サーバに一時保存し、ピクチャのサーバ側IDを返し、バックエンドのアップロードインタフェースに最後にピクチャのサーバアドレスを取得するように要求する.

chooseImage(photoMustTake) {
 return new Promise(resolve => {
  var sourceType = (photoMustTake && photoMustTake == 1) ? ['camera'] : ['album', 'camera']
  wx.chooseImage({
   count: 1, //   9
   sizeType: ['original', 'compressed'], //             ,      
   sourceType: sourceType, //              ,      
   success: function (res) {
    //          ID  ,localId    img   src      
    wx.uploadImage({
     localId: res.localIds[0],
     isShowProgressTips: 1,
     success: function (upRes) {
      const formdata={mediaId:upRes.serverId}
      uploadImageByWx(qs.stringify(formdata)).then(osRes => {
       resolve(osRes.data)
      })
     },
     fail: function (res) {
     // alert(JSON.stringify(res));
     }
    });
   }
  });
 })
}

チャットルーム断線再接続の処理
バックエンドに自動断線時間が設定されているため、socket断線自動再接続が必要です.
dataでは、beginTimeは現在の実時間を表し、サーバ時間と同期するために使用され、openTimeはsocket作成時間を表し、主にページング、再接続時の判断に使用され、reconnectionは断線再接続の有無を表します.

data() {
 return {
  reconnection: false,
  beginTime: null,
  openTime: null
 }
}

SOcket接続を初期化するとopenTimeが現在のローカル時間に割り当てられ、socket接続に成功した後、beginTimeがサーバから返される現在時間に割り当てられ、タイマがサーバと一致するように設定されます.
メッセージを送信する場合、複数のユーザがいる場合、各ユーザのシステムのローカル時間が異なり、メッセージの順序が乱れます.したがって、beginTimeパラメータを送信してユーザが送信した時間を記録する必要があり、各ユーザのbeginTimeはサーバ時間と同期しており、この問題を解決することができる.
チャットルームではページングが必要ですが、異なる時刻にページングされたデータは異なります.たとえば、現在時刻に10個のメッセージがあり、次の時刻に2個のデータが追加されます.したがって、ページングデータを要求するときは、socketを作成する時間をクエリー基準としてopenTimeパラメータを渡します.

//   socket
createSocket() {
 _that.openTime = new Date().getTime() //   socket     
 _that.socket = new WebSocket(...)
}

// socket         
COMMAND_LOGIN_RESP(data) {
 if(10007 == data.code) { //     
  this.page.beginTime = data.user.updateTime //     
  this.timeClock()
 }
}
//          
timeClock() {
 this.timer = setInterval(() => {
  this.page.beginTime = this.page.beginTime + 1000
 }, 1000)
}

SOcketが切断された場合、beginTimeと現在の時間が60秒を超えているかどうかを判断し、超えていない場合は非正常な切断接続として処理しない.

_that.socket.onerror = evt => {
 if (!_that.page.beginTime) {
  _that.$vux.toast.text('   ,     ')
  return false
 }
 //    
 if (this.noConnection == true) {
  return false
 }
 // socket    
 var date = new Date().getTime()
 //           60 
 if (date - _that.openTime > 60000) {
  _that.reconnection = true
  _that.createSocket()
 }
}

オーディオ送信時の初回ライセンスの問題
オーディオを送信場合、最初のクリックはフレームを弾いて権限を提示し、クリックの許可にかかわらず、拒否にかかわらずwxを実行する.startRecord()は、前回の録音が終了していないため、録音方法がtouchstartイベントによってトリガーされるため、touchcancelイベントを使用してポップアッププロンプトの許可状態をキャプチャすることができます.

_that.$refs.btnVoice.addEventListener("touchcancel" ,function(event) {
 event.preventDefault()
 //      touchend
 _that.voice.isUpload = false
 _that.voice.voiceText = '     '
 _that.voice.touchStart = false
 _that.stopRecord()
})

コンポーネントの破棄時にタイマーが空になっていません
コンポーネントインスタンスが破棄された後もsetInterval()は実行され続け、手動で消去する必要があります.そうしないとメモリが消費されます.

mounted(){
 this.timer = (() => {
  ...
 }, 1000)
},
//   beforeDestroy()          
 
beforeDestroy() {
 clearInterval(this.timer)  
 this.timer = null
}

ウォッチリスナーの変化

watch: {
 chatList: {
  deep: true, //        
  handler: function (newVal,oldVal){
   ...
  }
 }
}

バックグラウンド管理システムテンプレートの問題
バックグラウンド管理システムがメニュー権限を追加したため、ルーティングはメニュー権限に基づいて動的に生成され、メニューの権限が1つしかない場合、このメニューが表示されない可能性があります.テンプレートのソースコードを参照してください.


 
  
  {{generateTitle(item.children[0].meta.title)}}
 
 

 
 

 
 

ここで、 v-if="hasOneShowingChildren(item.children) && !item.children[0].children&&!item.alwaysShow" は、このノードにサブエレメントが1つしかなく、このノードの最初のサブエレメントにサブエレメントがない場合に、特別なメニュースタイルが表示されることを示す.問題は、 item.children[0] が非表示のメニュー(item.hidden==true)である可能性があるため、この式が成立すると、非表示のメニューがレンダリングされる可能性があります.最新のバックグラウンドソースを参照すると、著者はこの問題を修復しました.

methods: {
 hasOneShowingChild(children = [], parent) {
  const showingChildren = children.filter(item => {
  if (item.hidden) {
   return false
  } else {
   // Temp set(will be used if only has one showing child)
   this.onlyOneChild = item
   return true
  }
  })
  // When there is only one child router, the child router is displayed by default
  if (showingChildren.length === 1) {
  return true
  }
  // Show parent if there are no child router to display
  if (showingChildren.length === 0) {
  this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
  return true
  }
  return false
 }
 }

ダイナミックコンポーネントの作成
似たようなコンポーネントがたくさんある場合がありますが、わずかな点で異なります.このようなコンポーネントをプロファイルに書き、コンポーネントを動的に作成して参照することができます.

var vm = new Vue({
 el: '#example',
 data: {
 currentView: 'home'
 },
 components: {
 home: { /* ... */ },
 posts: { /* ... */ },
 archive: { /* ... */ }
 }
})

 

ダイナミックメニュー権限
メニューは権限に基づいて動的に生成されるため、デフォルトのルーティングは権限判断を必要としないページがいくつか必要であり、他のページのルーティングは1つのmapオブジェクトasyncRouterMapに配置され、
roleを権限に対応する符号化に設定する

export const asyncRouterMap = [
 {
  path: '/project',
  component: Layout,
  redirect: 'noredirect',
  name: 'Project',
  meta: { title: '    ', icon: 'project' },
  children: [
   {
    path: 'index',
    name: 'Index',
    component: () => import('@/views/project/index'),
    meta: { title: '    ', role: 'PRO-01' }
   },

ナビゲーションガードの判断は、tokenおよびstore.getters.allowGetRole がユーザがログインしたことを示す場合、routersはユーザが権限に基づいて生成するルーティングツリーであり、存在しない場合、store.dispatch('GetMenu') を呼び出してユーザメニュー権限を要求し、storeを呼び出す.dispatch('GenerateRoutes')は、取得したメニュー権限をルーティングの構造に解析します.

router.beforeEach((to, from, next) => {
 if (whiteList.indexOf(to.path) !== -1) {
  next()
 } else {
  NProgress.start()
  //      token               
  if (getToken() && store.getters.allowGetRole) {
   if (to.path === '/login') {
    next({ path: '/' })
    NProgress.done()
   } else {
    if (!store.getters.routers.length) {
     //         
     store.dispatch('GetMenu').then(() => {
      //          
      store.dispatch('GenerateRoutes').then(() => {
       router.addRoutes(store.getters.addRouters)
       next({ ...to, replace: true })
      })
     })
    } else {
     next()
    }
   }
  } else {
   next('/login')
   NProgress.done()
  }
 }
})

storeのactions

//           
GetMenu({ commit, state }) {
 return new Promise((resolve, reject) => {
  getMenu().then(res => {
   commit('SET_MENU', res.data)
   resolve(res)
  }).catch(error => {
   reject(error)
  })
 })
},
//            
GenerateRoutes({ commit, state }) {
 return new Promise(resolve => {
  //          
  var accessedRouters = []
  asyncRouterMap.forEach((item, index) => {
   if (item.children && item.children.length) {
    item.children = item.children.filter(child => {
     if (child.hidden) {
      return true
     } else if (hasPermission(state.role.menu, child)) {
      return true
     } else {
      return false
     }
    })
   }
   accessedRouters[index] = item
  })
  //           vuex 
  commit('SET_ROUTERS', accessedRouters)
  resolve()
 })
},

プロジェクトの導入とバージョン切り替え
現在、プロジェクトには2つの環境があり、それぞれテスト環境と生産環境であり、要求されたインタフェースアドレスはsrcutilsglobalに配置されている.jsでは、本番環境を導入する際にdevelopブランチのコードをmasterブランチ、globalにマージするだけでよい.jsアドレスを追加する必要はありません
まとめ
以上述べたのは編集者が皆さんに紹介したvueプロジェクトの先端知識点の整理で、皆さんに役に立つことを望んでいます.もし皆さんが何か疑問があれば、私にメッセージを送ってください.編集者はすぐに皆さんに返事します.