<font id="zqva1"></font>
<rt id="zqva1"></rt>
  • <tt id="zqva1"></tt>
    <cite id="zqva1"></cite>

    <cite id="zqva1"><noscript id="zqva1"></noscript></cite>
      <rp id="zqva1"><meter id="zqva1"></meter></rp>

        <cite id="zqva1"></cite>
          <b id="zqva1"></b>
          <rp id="zqva1"></rp>
          <cite id="zqva1"></cite>

          <rt id="zqva1"></rt>

        1. <rp id="zqva1"></rp>

          VueJS 實際開發中會遇到的問題

          時間:?2017-11-09閱讀:?1818標簽:?vue作者:?熊D01001

          由于公司的前端開始轉向 VueJS,最近開始使用這個框架進行開發,遇到一些問題記錄下來,以備后用。

          主要寫一些 官方手冊 上沒有寫,但是實際開發中會遇到的問題,需要一定知識基礎。


          涉及技術棧


          正文:

          polyfill 與 transform-runtime

            首先,vue-cli 為我們自動添加了 babel-plugin-transform-runtime 這個插件,該插件多數情況下都運作正常,可以轉換大部分 ES6 語法。

            但是,存在如下兩個問題:

          1. 異步加載組件時,會產生 polyfill 代碼冗余
          2. 不支持對全局函數與實例方法的 polyfill

            兩個問題的原因均歸因于 babel-plugin-transform-runtime 采用了沙箱機制來編譯我們的代碼(即:不修改宿主環境的內置對象)。

            由于異步組件最終會被編譯為一個單獨的文件,所以即使多個組件中使用了同一個新特性(例如:Object.keys()),那么在每個編譯后的文件中都會有一份該新特性的 polyfill 拷貝。如果項目較小可以考慮不使用異步加載,但是首屏的壓力會比較大。

            不支持全局函數(如:Promise、Set、Map),Set 跟 Map 這兩種數據結構應該大家用的也不多,影響較小。但是 Promise 影響可能就比較大了。

            不支持實例方法(如:'abc'.includes('b')、['1', '2', '3'].find((n) => n < 2) 等等),這個限制幾乎廢掉了大部分字符串和一半左右數組的新特性。

          一般情況下 babel-plugin-transform-runtime 能滿足大部分的需求,當不滿足需求時,推薦使用完整的 babel-polyfill。

          替換 babel-polyfill

            首先,從項目中移除 babel-plugin-transform-runtime
            卸載該依賴:

          npm un babel-plugin-transform-runtime -D

            修改 babel 配置文件

          // .babelrc
          {
            //...
            "plugins": [
              // - "transform-runtime"
            ]
            //...
          }

            然后,安裝 babel-polyfill 依賴:

          npm i babel-polyfill -D

            最后,在入口文件中導入

          // src/main.js
          import 'babel-polyfill'

          ES6 import 引用問題

            在 ES6 中,模塊系統的導入與導出采用的是引用導出與導入(非簡單數據類型),也就是說,如果在一個模塊中定義了一個對象并導出,在其他模塊中導入使用時,導入的其實是一個變量引用(指針),如果修改了對象中的屬性,會影響到其他模塊的使用。

            通常情況下,系統體量不大時,我們可以使用 JSON.parse(JSON.stringify(str)) 簡單粗暴地來生成一個全新的深度拷貝的 數據對象。不過當組件較多、數據對象復用程度較高時,很明顯會產生性能問題,這時我們可以考慮使用 Immutable.js

          鑒于這個原因,進行復雜數據類型的導出時,需要注意多個組件導入同一個數據對象時修改數據后可能產生的問題。
          此外,模塊定義變量或函數時即便使用 let 而不是 const,在導入使用時都會變成只讀,不能重新賦值,效果等同于用 const 聲明。

          在 Vue 中使用 Pug 與 Less

          安裝依賴

            Vue 中使用 vue-loader 根據 lang 屬性自動判斷所需要的 loader,所以不用額外配置 Loader,但是需要手動安裝相關依賴:

          npm i pug -D
          npm i less-loader -D

          還是相當方便的,不用手動修改 webpack 的配置文件添加 loader 就可以使用了

          使用 pug 還是 pug-loader?sass 兩種語法的 loader 如何設置?
          --- 請參考 預處理器 · vue-loader

          使用

          <!-- xxx.vue -->
          <style lang="less">
            .action {
              color: #ddd;
                ul {
                  overflow: hidden;
                  li {
                    float: left;
                  }
                }
            }
          </style>
          <template lang="pug">
            .action(v-if='hasRight')
              ul
                li 編輯
                li 刪除
          </template>
          <script>
            export default {
              data () {
                return {
                  hasRight: true
                }
              }
            }
          </script>

          定義全局函數或變量

            許多時候我們需要定義一些全局函數或變量,來處理一些頻繁的操作(這里拿 AJAX 的異常處理舉例說明)。但是在 Vue 中,每一個單文件組件都有一個獨立的上下文(this)。通常在異常處理中,需要在視圖上有所體現,這個時候我們就需要訪問 this 對象,但是全局函數的上下文通常是 window,這時候就需要一些特殊處理了。

          簡單粗暴型

            最簡單的方法就是直接在 window 對象上定義一個全局方法,在組件內使用的時候用 bind、call 或 apply 來改變上下文。

            定義一個全局異常處理方法:

          // errHandler.js
          window.errHandler = function () { // 不能使用箭頭函數
            if (err.code && err.code !== 200) {
              this.$store.commit('err', true)
            } else {
              // ...
            }
          }

            在入口文件中導入:

          // src/main.js
          import 'errHandler.js'

            在組件中使用:

          // xxx.vue
          export default {
            created () {
              this.errHandler = window.errHandler.bind(this)
            },
            method: {
              getXXX () {
                this.$http.get('xxx/xx').then(({ body: result }) => {
                  if (result.code === 200) {
                    // ...
                  } else {
                    this.errHandler(result)
                  }
                }).catch(this.errHandler)
              }
            }
          }

          優雅安全型

            在大型多人協作的項目中,污染 window 對象還是不太妥當的。特別是一些比較有個人特色的全局方法(可能在你寫的組件中幾乎處處用到,但是對于其他人來說可能并不需要)。這時候推薦寫一個模塊,更優雅安全,也比較自然,唯一不足之處就是每個需要使用該函數或方法的組件都需要進行導入。

            使用方法與前一種大同小異,就不多作介紹了。 ̄ω ̄=

          Moment.JS 與 Webpack

            在使用 Moment.js 遇到一些問題,發現最終打包的文件中將 Moment.js 的全部語言包都打包了,導致最終文件徒然增加 100+kB。查了一下,發現可能是 webpack 打包或是 Moment.js 資源引用問題(?),目前該問題還未被妥善處理,需要通過一些 trick 來解決這個問題。

            在 webpack 的生產配置文件中的 plugins 字段中添加一個插件,使用內置的方法類 ContextReplacementPlugin 過濾掉 Moment.js 中那些用不到的語言包:

          // build/webpack.prod.conf.js
          new webpack.ContextReplacementPlugin(/moment[\\/]locale$/, /^\.\/(zh-cn)$/)

          解決方案采自 oleg-nogin@webpack/webpack#3128
          問題討論詳見 GitHub Issue: moment/moment#2373webpack/webpack#3128

          自定義路徑別名

            可能有些人注意到了,在 vue-cli 生成的模板中在導入組件時使用了這樣的語法:

          import Index from '@/components/Index'

            這個 @ 是什么東西?后來改配置文件的時候發現這個是 webpack 的配置選項之一:路徑別名。

            我們也可以在基礎配置文件中添加自己的路徑別名,比如下面這個就把 ~ 設置為路徑 src/components 的別名:

          // build/webpack.base.js
          {
            resolve: {
              extensions: ['.js', '.vue', '.json'],
              alias: {
                'vue$': 'vue/dist/vue.esm.js',
                '@': resolve('src'),
                '~': resolve('src/components')
              }
            }
          }

            然后我們導入組件的時候就可以這樣寫:

          // import YourComponent from 'YourComponent'
          // import YourComponent from './YourComponent'
          // import YourComponent from '../YourComponent'
          // import YourComponent from '/src/components/YourComponent'
          import YourComponent from '~/YourComponent'

            既解決了路徑過長的麻煩,又解決了相對路徑的煩惱,方便很多吧!ヾ(???ゞ)

          CSS 作用域與模塊

          組件內樣式

            通常,組件中 <style></style> 標簽里的樣式是全局的,在使用第三方 UI 庫(如:Element)時,全局樣式很可能影響 UI 庫的樣式。

            我們可以通過添加 scoped 屬性來使 style 中的樣式只作用于當前組件:

          <style lang="less" scoped>
            @import 'other.less';
            .title {
              font-size: 1.2rem;
            }
          </style>

          在有 scoped 屬性的 style 標簽內導入其他樣式,同樣會受限于作用域,變為組件內樣式。復用程度較高的樣式不建議這樣使用。

          另,在組件內樣式中應避免使用元素選擇器,原因在于元素選擇器與屬性選擇器組合時,性能會大大降低。

          --- 兩種組合選擇器的測試:classes selectorelements selector

          導入樣式

            相對于 style 使用 scoped 屬性時的組件內樣式,有時候我們也需要添加一些全局樣式。當然我們可以用沒有 scoped 屬性的 style 來寫全局樣式。

            但是相比較,更推薦下面這種寫法:

          /* 單獨的全局樣式文件 */
          /* style-global.less */
          body {
            font-size: 10px;
          }
          .title {
            font-size: 1.4rem;
            font-weight: bolder;
          }

            然后在入口文件中導入全局樣式:

          // src/main.js
          import 'style-global.less'

          獲取表單控件值

            通常我們可以直接使用 v-model 將表單控件與數據進行綁定,但是有時候我們也會需要在用戶輸入的時候獲取當前值(比如:實時驗證當前輸入控件內容的有效性)。

            這時我們可以使用 @input 或 @change 事件綁定我們自己的處理函數,并傳入 $event 對象以獲取當前控件的輸入值:

          <input type='text' @change='change($event)'>
          change (e) {
            let curVal = e.target.value
            if (/^\d+$/.test(curVal)) {
              this.num = +curVal
            } else {
              console.error('%s is not a number!', curVal)
            }
          }

          當然,如果 UI 框架采用 Element 會更簡單,它的事件回調會直接傳入當前值。

          v-for 的使用 tips

            v-for 指令很強大,它不僅可以用來遍歷數組、對象,甚至可以遍歷一個數字或字符串。

            基本語法就不講了,這里講個小 tips:

          索引值

            在使用 v-for 根據對象或數組生成 DOM 時,有時候需要知道當前的索引。我們可以這樣:

          <ul>
            <li v-for='(item, key) in items' :key='key'> {{ key }} - {{ item }}
          </ul>

            但是,在遍歷數字的時候需要注意,數字的 value 是從 1 開始,而 key 是從 0 開始:

          <ul>
            <li v-for='(v, k) in 3' :key='k'> {{ k }}-{{ v }} 
            <!-- output to be 0-1, 1-2, 2-3 -->
          </ul>

          2.2.0+ 的版本里,當在組件中使用 v-for 時,key 現在是必須的。

          模板的唯一根節點

            與 JSX 相同,組件中的模板只能有一個根節點,即下面這種寫法是 錯誤 的:

          <template>
            <h1>Title</h1>
            <article>Balabala...</article>
          </template>

            我們需要用一個塊級元素把他包裹起來:

          <template>
            <div>
              <h1>Title</h1>
              <article>Balabala...</article>
            </div>
          </template>

          原因參考:React-小記:組件開發注意事項#唯一根節點

          項目路徑配置

            由于 vue-cli 配置的項目提供了一個內置的靜態服務器,在開發階段基本不會有什么問題。但是,當我們把代碼放到服務器上時,經常會遇到靜態資源引用錯誤,導致界面一片空白的問題。

            這是由于 vue-cli 默認配置的 webpack 是以站點根目錄引用的文件,然而有時候我們可能需要把項目部署到子目錄中。

            我們可以通過 config/index.js 來修改文件引用的相對路徑:

            build.assetsSubDirectory: 'static'
            build.assetsPublicPath: '/'
          
            dev.assetsSubDirectory: 'static'
            dev.assetsPublicPath: '/'

            我們可以看到導出對象中 build 與 dev 均有 assetsSubDirectory、assetsPublicPath 這兩個屬性。

            其中 assetsSubDirectory 指靜態資源文件夾,也就是打包后的 js、css、圖片等文件所放置的文件夾,這個默認一般不會有問題。

            assetsPublicPath 指靜態資源的引用路徑,默認配置為 /,即網站根目錄,與 assetsSubDirectory 組合起來就是完整的靜態資源引用路徑 /static。

            寫到這里解決方法已經很明顯了,只要把根目錄改為相對目錄就好了:

            build.assetsSubDirectory: 'static'
            build.assetsPublicPath: './'

            沒錯!就是一個 . 的問題。ㄟ( ▔, ▔ )ㄏ

          更小的 Polyfill 開銷

            在引入 Polyfill 之后,可以在 .babelrc 文件中開啟 useBulitIns 屬性。啟用該屬性后,編譯項目時會根據項目中新特性的使用情況將完整的 polyfill 拆分成獨立的模塊序列。
            啟用 useBuiltIns 屬性:

            // .babelrc
            {
              "presets": [
                ["env", {
                  "modules": false,
                  "useBuiltIns": true
                }],
                "es2015",
                "stage-2"
              ]
              // ...
            }

            安裝后引入 babel-polyfill:

            // src/main.js
            import 'babel-polyfill'
          
            [1, 2, 3].find((v => v > 2))

          啟用 useBulitIns 后自動拆分 babel-polyfill

            import 'core-js/modules/es6.array.find'
          
            [1, 2, 3].find((v => v > 2))

          經測試最大減少了一半左右的 polyfill 體積
          沒深入研究哈,猜測可能加了 core-js 跟一些基礎的 polyfill

          使用 ESnext class 特性

          對比

            默認時,Vue 單文件組件使用一個對象來描述組件內部的實現:

            const App = {
              // initialized data
              data () {
                return {
                  init: false
                }
              }
              // lifecycle hook
              created () {}
              mounted () {}
              // ...
            }
          
            export default App

            我們可以通過安裝一些依賴來支持最新的 class 寫法:

            import Vue from 'vue'
            import Component from 'vue-class-component'
          
            @Component
            class App extends Vue {
              init = false;
              created () {}
              mounted () {}
            }
          
            export default App

          不可否認,確實多些了一些代碼哈,不過個人還是比較傾向新語法特性的寫法的,畢竟標準即是燈塔
          P.S 這里使用了還處于 Stage 3 的 Field declarations 來聲明組件的初始 data

          使用

            下面來看看需要做哪些改動以支持使用 class 的寫法:

          1. 首先,最明顯的就是我們需要 vue-class-component 這個依賴了。
          2. 然后,這個依賴需要 babel 的 transform-decorators-legacy 插件支持。
          3. 最后,如果你也想使用 Field declarations 字段聲明寫法,再添加一個 transform-class-properties 就好了。

            安裝依賴:

            npm i vue-class-component -D
            npm i babel-plugin-transform-decorators-legacy -D
            npm i babel-plugin-transform-class-properties -D

            配置 babel

            // .babelrc
            {
              // ...
              "plugins": [
                "transform-runtime",
                "transform-decorators-legacy",
                "transform-class-properties"
              ]
              // ...
            }

          注意:transform-decorators-legacy 需放在 transform-class-properties 之前

          響應式數據失效

          數組

            由于 Vue.js 響應式數據依賴于對象方法 Object.defineProperty。但很明顯,數組這個特殊的“對象”并沒有這個方法,自然也無法設置對象屬性的 descriptor,從而也就沒有 getter() 和 setter() 方法。所以在使用數組索引角標的形式更改元素數據時(arr[index] = newVal),視圖往往無法響應式更新。
            為解決這個問題,Vue.js 中提供了 $set() 方法:

          vm.arr.$set(0, 'newVal')
          // vm.arr[0] = 'newVal'

          對象

          受現代 JavaScript 的限制(以及廢棄 Object.observe),Vue 不能檢測到對象屬性的添加或刪除。由于 Vue 會在初始化實例時對屬性執行 getter/setter 轉化過程,所以屬性必須在 data 對象上存在才能讓 Vue 轉換它,這樣才能讓它是響應的。
          Ref: 深入響應式原理 - Vue.js

          var vm = new Vue({
            data: {
              a: 1
            }
          })
          // `vm.a` 是響應的
          vm.b = 2
          // `vm.b` 是非響應的

          靜態類型檢測

            推薦在開發較復雜的組件時使用 props 靜態類型檢測,提高組件的健壯性,多數情況下可以在轉碼階段提前發現錯誤。

          // before
          prop: [
            'id',
            'multiple',
            'callback',
          ]
          // after
          props: {
            id: {
              type: [ Number, Array ],
              required: true,
            },
            multiple: {
              type: Boolean,
              default: false,
            },
            callback : Function,
          }

          異步組件

            使用處于 Stage.3 階段的動態導入函數 import(),同時借助 webpack 的代碼分割功能,在 Vue.js 中我們可以很輕松地實現一個異步組件。

          異步路由組件

          const AsyncComponent = () => import('./AsyncComponent')

          異步組件工廠

          Vue.component(
            'async-webpack-example',
            () => import('./my-async-component')
          )

          相比于異步路由組建,異步組件工廠一般適用于組件內進一步小顆粒度的拆分處理,如:大體量組件內初次加載時的非必要組件(組件內嵌套的彈窗組件或 Popover 組件等)。

          吐血推薦

          1.站長廣告聯盟: 整理了目前主流的廣告聯盟平臺,如果你有流量,可以作為參考選擇適合你的平臺點擊進入...

          2.休閑娛樂: 直播/交友    優惠券領取   網頁游戲   H5游戲

          鏈接: http://www.modern-decoration.com.cn/article/detial/71

          vue中is的作用和用法

          總所周知,ul里面嵌套li的寫法是html語法的固定寫法(還有如table,select等)。my-component是我們自己寫的組件,但是html在渲染dom的時候,my-component對ul來說并不是有效的dom,甚至會報錯。

          一點 Vue.observable 想法

          Vue 2.6.0 新增了 Vue.observable api,但最近才去嘗試使用它。這東西說新也不新,因為他就是 vue 本身的功能,只是暴露出來,成為新 api 了。在老版本中,直接用 new Vue({ data: {} }) 也一樣。

          Vue.use到底是什么?

          我們在使用Vue做項目開發的時候,看到不少輪子都是通過Vue.use來進行使用,感覺甚是高大上。不過Vue.use到底是什么鬼?不妨來看個究竟。

          Vue.js最佳實踐:五招讓你成為Vue.js大師

          本文面向對象是有一定Vue.js編程經驗的開發者。如果有人需要Vue.js入門系列的文章可以在評論區告訴我,有空就給你們寫。對大部分人來說,掌握Vue.js基本的幾個API后就已經能夠正常地開發前端網站

          vue介紹

          庫是一種插件,是一種封裝好的特定方法的集合。提供給開發者使用,控制器在使用者手里。框架是一套架構,會基于自身特定向用戶提供一套相當完整的解決方案,控制權在框架本身

          vue有時候你不需要 $emit & $on

          在此之前,子組件到父組件的傳遞事件我一般還是使用 $emit 和 $on,因為這個操作理解起來并不難,代碼一般也挺清晰。不過今天遇到這么個情況 ——

          Vue最佳實踐

          Vue 最佳實踐,是參考 Vue 官方風格指南并根據過去 Vue 實際項目開發中的經驗總結的一套規范建議。本項目的目的是希望每個 Vue 開發者都能盡快熟悉并上手項目代碼,志在幫助 Vue 新手開發者及時避免一些不規范的設計和由此而引發的問題

          vue知識點總匯

          keep-alive它是vue的內置組件在默認情況下,v-model 在每次 input 事件觸發后將輸入框的值與數據進行同步 。你可以添加 lazy 修飾符,從而轉變為使用 change 事件進行同步:

          vue中使用v-for時為什么不能用index作為key?

          Vue 和 React 都實現了一套虛擬DOM,使我們可以不直接操作DOM元素,只操作數據便可以重新渲染頁面。而隱藏在背后的原理便是其高效的Diff算法。Vue 和 React 的虛擬DOM的Diff算法大致相同,其核心是基于兩個簡單的假設

          vue.extend拓展

          Vue.extend返回的是一個“拓展實例構造器”,也就是預設了部分選項的Vue實例構造器。經常服務于Vue.component用來生成組件,可以簡單理解為當在模板中遇到該組件名稱作為標簽的自定義元素時

          fly63.com版權所有,內容以共享、參考、研究為目的,不存在任何商業目的。其版權屬原作者所有,如有侵權,請與小編聯系!情況屬實本人將予以刪除!

          文章投稿關于web前端網站點搜索站長推薦網站地圖站長QQ:522607023

          小程序專欄: 土味情話心理測試腦筋急轉彎幽默笑話段子句子語錄成語大全

          国产精品高清视频免费 - 视频 - 在线观看 - 影视资讯 - 唯爱网