移動web開發能用vue嗎

2022-12-15 14:00:37

移動web開發能用vue。Vue是一個開源JavaScript框架,能夠開發單頁面應用程式;它可以用作Web應用程式框架,旨在簡化Web開發。vue支援行動端開發,適合製作行動端的Webapp;其入門成本低、快速上手,可以結合i-view、Element UI等成熟前端UI庫一起開發。

前端(vue)入門到精通課程,老師線上輔導:聯絡老師
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API偵錯工具:

本教學操作環境:windows7系統、vue3版,DELL G3電腦。

Vue.js是一個開源JavaScript框架,能夠開發單頁面應用程式。它還可以用作Web應用程式框架,旨在簡化Web開發。Vue.js應用程式開發引起了全球開發人員的極大關注,以構建令人驚歎的Web應用程式。

Vue.js的流行有很多原因,其中一個關鍵原因是它能夠在沒有任何動作的情況下重新渲染。它允許您構建可重用,小巧但功能強大的元件,因此,它提供了一個可組合的框架,允許您在需要時新增元件。

vue.js支援行動端開發,適合製作行動端的Webapp。針對於行動端,首選vue;入門成本低,快速上手,可以結合 i-view, Element UI等一些成熟的前端UI庫一起開發。

app很簡單,使用vuejs自不必說,元件開發模組管理使用vue-loader、webpack,頁面切換以及過場動畫使用vue-router,在app開發過程只需關注app的資料走向即可,另外可以搭配各類UI庫讓應用更加美觀,使用SUI或Framework7都可以,常使用的是Framework7一個分支版本light7(因為後續的功能補充可能用到jQuery。 【相關推薦:】

vue行動端開發總結

行動端適配

相對於PC端來說,行動端裝置解析度百花齊放,千奇百怪,對於每一個開發者來說,行動端適配是我們進行行動端開發第一個需要面對的問題。

在行動端我們經常可以在head標籤中看到這段程式碼:

<meta name='viewport' content='width=device-width,initial-scale=1,user-scale=no' />
登入後複製

通過meta標籤對viewport的設定,定義了頁面的縮放比例;要了解這些引數的意義,我們需要先知道幾個視口寬度的意義。

  • layoutviewport佈局寬度,就是網頁的寬度
  • visualviewport可是寬度,就是瀏覽器視窗的寬度,這個值決定了我們手機一屏能看到的內容;visualviewportlayoutviewport的大小關係,決定了是否會出現卷軸,當visualviewport更大或者剛好等於layoutviewport時是不會出現卷軸的。
  • idealviewport為瀏覽器定義的可完美適配行動端的viewport,固定不變,可以認為是裝置視口寬度device-width

meta的設定其實就是對layoutviewportvisualviewport進行設定。

  • width=device-width表示頁面寬度layoutviewport與裝置視口寬度idealviewport一致
  • initial-scale=1表示頁面寬度和網頁寬度與裝置視口寬度的初始縮放比例,visualviewport由這個比例決定,但是對於layoutviewport來說,它同時受到兩個屬性的影響,然後取其中較大的那個值。
  • user-scale=no禁止縮放

所以現在我們知道,這段在行動端常見的程式碼的意思,即將visualviewportlayoutviewport設定為idealviewport的值;這樣我們在行動端就不會出現卷軸,網頁內容可以比較好的展示出來,在這個前提下我們再考慮頁面的適配問題。

UI出圖的時候一般是有一個固定的寬度的,而我們實際的行動端裝置的寬度卻都不太一樣,但是如果頁面元素的縮放比例和頁面寬度的縮放比例一致,在不同尺寸的裝置下我們網頁的效果也將會是一致的。

使用相對單位

  • rem

rem 是相對於根元素 html 的 font-size 來做計算。通常在頁面初始化時載入時通過對document.documentElement.style.fontSize 設定來實現。一般我們將根元素html的font-size設定為寬度的1/10,不同裝置的寬度不同,但是同樣數值的rem比例與裝置的寬度比例是一致的。

document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';
登入後複製

在實際專案中我們無須在開發中自己進行轉換,可以使用pxtorem在輸出的時候將px轉換為rem。

  • 視口單位

將視口寬度window.innerWidth和視口高度window.innerHeight(即layoutviewport)等分為 100 份。

vw : 1vw 為視口寬度的 1% vh : 1vh 為視口高度的 1% vmin : vw 和 vh 中的較小值 vmax : 選取 vw 和 vh 中的較大值

和rem相比較,視口單位不需要使用js對根元素進行設定,相容性稍差,但是大部分裝置都已經支援了,同樣的無須再開發時進行單位換算,直接使用相關的外掛postcss-px-to-viewport在輸出的時候進行轉換。

1.png

修改viewport

之前我們提到了layoutviewport佈局寬度實際上不是一個固定值,而是通過meta設定屬性,通過idealviewport計算出來的值,我們可以通過控制meta的屬性來將layoutviewport固定為某一個值。一般設計圖的寬度為750px,現在我們的目標就是將layoutviewport設定為750px;layoutviewport受到兩個屬性的影響,width屬性我們之間設定為750,initial-scale縮放比例應該為idealviewport的寬度/750;當我們未改變meta標籤屬性的時候,layoutviewport的值其實就是idealviewport的值,所以可以通過document.body.clientWidth或者window.innerWidth來獲取。

;(function () {
    const width = document.body.clientWidth || window.innerWidth
    const scale = width / 750
    const content = 'width=750, initial-scale=' + scale + ', minimum-scale=' + scale + ', maximum-scale=' + scale + ', viewport-fit=cover'
    document.querySelector('meta[name="viewport"]').content = content
})()
登入後複製

設定完成之後,layoutviewport在不同的裝置中會始終保持為750px,我們開發時可以直接使用設計稿尺寸。

佈局樣式

佈局的方式可以是各種各樣的,但是出於相容性的考慮,有些樣式我們最好避免使用,難以解決的問題,那就不去面對。

需要謹慎對待的fixed

position:fixed在日常的頁面佈局中非常常用,在許多佈局中起到了關鍵的作用。它的作用是:position:fixed的元素將相對於螢幕視口(viewport)的位置來指定其位置。並且元素的位置在螢幕捲動時不會改變。 但是,在許多特定的場合,position:fixed的表現與我們想象的大相徑庭。

  • iOS彈出鍵盤;軟鍵盤喚起後,頁面的 fixed元素將失效(iOS認為使用者更希望的是元素隨著捲動而移動,也就是變成了 absolute 定位),既然變成了absolute,所以當頁面超過一屏且捲動時,失效的 fixed 元素就會跟隨捲動了。

  • 當元素祖先的 transform 屬性非 none 時,定位容器由視口改為該祖先。說的簡單點,就是position:fixed的元素會相對於最近的並且應用了transform的祖先元素定位,而不是視窗。導致這個現象的原因是使用了transform的元素將建立一個新的堆疊上下文。堆疊上下文(Stacking Context):堆疊上下文是 HTML 元素的三維概念,這些 HTML 元素在一條假想的相對於面向(電腦螢幕的)視窗或者網頁的使用者的 z 軸上延伸,HTML 元素依據其自身屬性按照優先順序順序佔用層疊上下文的空間。順序如下圖所示,總之堆疊上下文會對定位關係產生影響。想要進一步可以檢視不受控制的 position:fixed

2.png

鍵盤彈出與使用transform屬性的情況在行動端是很常見的,所以需要謹慎使用position:fixed

推薦使用flex

3.png

flex,即彈性佈局,行動端相容性較好,能夠滿足大部分佈局需求。現在我們使用flex來實現h5中常見的頂部標題列+中部捲動內容+底部導航欄的佈局;實現效果如下:

4.png

首先我們來實現整體的佈局,整體佈局應該是一個方向為flex-direction: column;並且佔據整個視窗的彈性盒子,然後裡面的佈局,應該是首尾為固定高度,中間內容區域為flex: 1;

html, body {
  padding: 0;
  margin: 0;
}
.page {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  .page-content {
    flex: 1;
    overflow-y: auto;
  }
}
登入後複製

然後再來實現底部標題列,底部標題列一般由居中標題和左右操作區域組成;為了實現中間區域標題居中,我們左右兩部分應該保持相同的寬度。

<template>
  <div>
    <div>
      左
    </div>
    <div>
      <slot>Title</slot>
    </div>
    <div>
      <div>右</div>
    </div>
  </div>
</template>
<script>
export default {
  name: 'HeadBar'
}
</script>
<style scoped>
.header {
  display: flex;
  width: 100%;
  line-height: 88px;
  height: 88px;
  font-size: 36px;
  background-color: #42b983;
  z-index: 999;
  color: #fff;
  transition: background-color .5s ease;
  .header__main {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
  }
  .header__left, .header__right {
    padding: 0 16px;
    width: 120px;
  }
  .header__left {
    text-align: left;
  }
  .header__right {
    text-align: right;
  }
}
</style>
登入後複製

底部導航欄主體部分,其實是單個導航選項平分導航欄;而每個導航選項,是一個方向為flex-direction: column;佈局方式橫向為align-items: center;,豎向為justify-content: space-around;

<template>
  <div>
    <div>
      <div></div>
      <span>選項1</span>
    </div>
    <div>
      <div></div>
      <span>選項2</span>
    </div>
    <div>
      <div></div>
      <span>選項3</span>
    </div>
    <div>
      <div></div>
      <span>選項4</span>
    </div>
  </div>
</template>
<script>
export default {
  name: 'BottomTaber',
  data () {
    return {
    }
  }
}
</script>
<style scoped>
.taber {
  background-color: #42b983;
  color: #fff;
  height: 88px;
  display: flex;
  .taber-item {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    align-items: center;
  }
  .icon {
    width: 36px;
    height: 36px;
    background-color: #fff;
  }
}
</style>
登入後複製

頁面跳轉

轉場動畫

在vue中我們通過vue-router來管理路由,每個路由跳轉類似與在不同的頁面之間進行切換,從使用者友好的角度來說,每次切換頁面的時候最好新增一個轉場效果。如果轉場動畫不區分路由是開啟新頁面、還是返回之前頁面我們只需要在<router-view>外使用<transition>新增一個動畫效果即可;但是一般開啟和返回是應用不同的動畫效果的,所以我們需要在切換路由的時候區分路由是前進還是後退。為了區分路由的動作,我們在路由檔案中設定meta為數位,meta表示其路由的深度,然後監聽$route,根據to、from meta值的大小設定不同的跳轉動畫。如果應用到多種跳轉動畫,可以根據詳情,具體情況具體應用。

<template>
  <transition :name="transitionName">
    <router-view></router-view>
  </transition>
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
      transitionName: 'fade'
    }
  },
  watch: {
    '$route' (to, from) {
      let toDepth = to.meta
      let fromDepth = from.meta
      if (fromDepth > toDepth) {
        this.transitionName = 'fade-left'
      } else if (fromDepth < toDepth) {
        this.transitionName = 'fade-right'
      } else {
        this.transitionName = 'fade'
      }
    }
  }
}
</script>
登入後複製

5.gif

雖然這樣能夠實現跳轉效果,但是需要在編寫router時新增設定,比較麻煩;我們可以使用開源專案vue-navigation來實現,更加方便,無須對router進行多餘的設定。npm i -S vue-navigation安裝,在main.js中匯入:

import Navigation from 'vue-navigation'
Vue.use(Navigation, {router}) // router為路由檔案
登入後複製

在App.vue中設定:

this.$navigation.on('forward', (to, from) => {
    this.transitionName = 'fade-right'
 })
 this.$navigation.on('back', (to, from) => {
    this.transitionName = 'fade-left'
 })
 this.$navigation.on('replace', (to, from) => {
    this.transitionName = 'fade'
 })
登入後複製

vue-navigation外掛還有一個重要的功能就是儲存頁面狀態,與keep-alive相似,但是keep-alive儲存狀態無法識別路由的前進後退,而實際應用中,我們的需求是返回頁面時,希望頁面狀態儲存,當進入頁面時希望獲取新的資料,使用vue-navigation可以很好的實現這個效果。具體使用可以檢視vue-navigation有詳細使用說明與案例。另外也可以嘗試vue-page-stack,兩個專案都能實現我們需要的效果,vue-page-stack借鑑了vue-navigation,也實現了更多的功能,並且最近也一直在更新。

PS: 這裡的動畫效果參照自animate.scss;

底部導航欄

之前我們已經實現了底部導航欄的基本樣式,這裡我們再做一些說明。當頁面路由路徑與router-link的路由匹配時,router-link將會被設定為啟用狀態,我們可以通過設定active-class來設定路徑啟用時應用的類名,預設為router-link-active,而啟用的類名還有一個router-link-exact-active,這個類名是由exact-active-class來設定的,同樣是設定路徑啟用時應用的類名;active-classexact-active-class其實是由路由的匹配方式決定的。

一般路由的匹配方式是包含匹配。 舉個例子,如果當前的路徑是 /a 開頭的,那麼 也會被設定 CSS 類名。按照這個規則,每個路由都會啟用 ,而使用exact屬性可以使用「精確匹配模式」。精確匹配只有當路由完全相同的時候才會被啟用。

路由守衛

行動端的路由守衛一般不會太複雜,主要是登入許可權的判斷,我們設定一個路由白名單,將所有不需要登入許可權的路由放入其中;對於需要登入的路由做判斷,沒有登入就跳轉登入頁面,要求使用者進行登入後在存取,如果登入後需要返回原有路由就把目標頁面的路由作為引數傳遞給登入頁面,再在登入後進行判斷,如果存在目標頁面引數就跳轉目標頁面,沒有就跳轉首頁。

如果你的應用涉及到許可權,那需要標註每個路由需要的許可權,在meta中設定roles,roles是陣列來儲存需要的許可權;從後臺的介面中獲取使用者擁有的許可權和roles進行對比就可以判斷是否具有相關許可權了。

const whiteList = ['/login']
router.beforeEach((to, from, next) => {
  const hasToken = store.getters.auth
  if (hasToken) {
    if (to.path === '/login') {
      next({ path: '/' })
    } else {
      const needRoles = to.meta && to.meta.roles && to.meta.roles.length > 0
      if (needRoles) {
        const hasRoles = store.state.user.roles.some(role => to.meta.roles.includes(role))
        if (hasRoles) {
          next()
        } else {
          next('/403')
        }
      } else {
        next()
      }
    }
  } else {
    if (whiteList.includes(to.path)) {
      next()
    } else {
      next('/login')
    }
  }
})
登入後複製

元件

自動載入

在我們的專案中,往往會使用的許多元件,一般使用頻率比較高的元件為了避免重複匯入的繁瑣一般是作為全域性元件在專案中使用的。而註冊全域性元件我們首先需要引入元件,然後使用Vue.component進行註冊;這是一個重複的工作,我們每次建立元件都會進行,如果我們的專案是使用webpack構建(vue-cli也是使用webpack),我們就可以通過require.context自動將元件註冊到全域性。建立components/index.js檔案:

export default function registerComponent (Vue) {
  /**
   * 引數說明:
   * 1. 其元件目錄的相對路徑
   * 2. 是否查詢其子目錄
   * 3. 匹配基礎元件檔名的正規表示式
   **/
  const modules = require.context('./', false, /\w+.vue$/)
  modules.keys().forEach(fileName => {
    // 獲取元件設定
    const component = modules(fileName)
    // 獲取元件名稱,去除檔名開頭的 `./` 和結尾的擴充套件名
    const name = fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
    // 註冊全域性元件
    // 如果這個元件選項是通過 `export default` 匯出的,
    // 那麼就會優先使用 `.default`,
    // 否則回退到使用模組的根。
    Vue.component(name, component.default || component)
  })
}
登入後複製

之後在main.js中匯入註冊模組進行註冊,使用require.context我們也可以實現vue外掛和全域性filter的匯入。

import registerComponent from './components'
registerComponent(Vue)
登入後複製

通過v-model繫結資料

v-model是語法糖,它的本質是對元件事件進行監聽和資料進行更新,是props和$on監聽事件的縮寫,v-model預設傳遞value,監聽input事件。現在我們使用v-model來實現下數位輸入框,這個輸入框只能輸入數位,在元件中我們只需要定義value來接受傳值,然後在輸入值滿足我們輸入條件(輸入為數位)的時候使用$emit觸發input事件。

<template>
  <div>
    <input type="text" :value="value" @input="onInput">
  </div>
</template>
<script>
export default {
  name: 'NumberInput',
  props: {
    value: String
  },
  methods: {
    onInput (event) {
      if (/^\d+$/.test(event.target.value)) {
        this.$emit('input', event.target.value)
      } else {
        event.target.value = this.value
      }
    }
  }
}
</script>
登入後複製

使用的時候,我們只需要使用v-model繫結值就可以了。v-model預設會利用名為valueprop和名為input的事件,但是很多時候我們想使用不同的prop和監聽不同的事件,我們可以使用model選項進行修改。

Vue.component('my-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    // this allows using the `value` prop for a different purpose
    value: String,
    // use `checked` as the prop which take the place of `value`
    checked: {
      type: Number,
      default: 0
    }
  },
  // ...
})
登入後複製
<my-checkbox v-model="foo" value="some value"></my-checkbox>
登入後複製

上述程式碼相當於:

<my-checkbox
  :checked="foo"
  @change="val => { foo = val }"
  value="some value">
</my-checkbox>
登入後複製

通過外掛的方式來使用元件

在很多第三方元件庫中,我們經常看到直接使用外掛的方式呼叫元件的方式,比如VantUI的Dialog彈出框元件,我們不但可以使用元件的方式進行使用,也可以通過外掛的形式進行呼叫。

this.$dialog.alert({
  message: '彈窗內容'
});
登入後複製

將元件作為外掛使用的原理其實並不複雜,就是使用手動掛載Vue元件範例。

import Vue from 'vue';
export default function create(Component, props) {
    // 先建立範例
    const vm = new Vue({
        render(h) {
            // h就是createElement,它返回VNode
            return h(Component, {props})
        }
    }).$mount();
    // 手動掛載
    document.body.appendChild(vm.$el);
    // 銷燬方法
    const comp = vm.$children[0];
    comp.remove = function() {
        document.body.removeChild(vm.$el);
        vm.$destroy();
    }
    return comp;
}
登入後複製

呼叫create傳入元件和props引數就可以獲取元件的範例,通過元件範例我們就可以呼叫元件的各種功能了。

<template>
  <div v-show="visible">
    載入中
  </div>
</template>
<script>
export default {
  name: 'Loading',
  data () {
    return {
      visible: false
    }
  },
  methods: {
    show () {
      this.visible = true
    },
    hide () {
      this.visible = false
    }
  }
}
</script>
<style scoped>
.loading-wrapper {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
  background-color: rgba(0, 0, 0, .4);
  z-index: 999;
}
</style>
<!--使用-->
const loading = create(Loading, {})
loading.show() // 顯示
loading.hide() // 關閉
登入後複製

第三方元件

行動端各種元件、外掛已經相對完善,在專案開發中重複造輪子是一件很不明智的事情;開發專案時我們可以藉助第三方元件、外掛提高我們的開發效率。

  • 常用元件庫

VantUI是有贊開源的一套輕量、可靠的行動端Vue元件庫;支援按需引入、主題客製化、SSR,除了常用元件外,針對電商場景還有專門的業務元件,如果是開發電商專案的話,推薦使用。官方檔案關於主題客製化是在webpack.config.js中進行設定的:

// webpack.config.js
module.exports = {
  rules: [
    {
      test: /\.less$/,
      use: [
        // ...其他 loader 設定
        {
          loader: 'less-loader',
          options: {
            modifyVars: {
              // 直接覆蓋變數
              'text-color': '#111',
              'border-color': '#eee'
              // 或者可以通過 less 檔案覆蓋(檔案路徑為絕對路徑)
              'hack': `true; @import "your-less-file-path.less";`
            }
          }
        }
      ]
    }
  ]
};
登入後複製

但我們的專案可能是使用vue-cli構建,這時我們需要在vue.config.js中進行設定:

module.exports = {
  css: {
    loaderOptions: {
      less: {
        modifyVars: {
          'hack': `true; @import "~@/assets/less/vars.less";`
        }
      }
    }
  }
}
登入後複製

另外vuxmint-ui也是很好的選擇。

  • 常用外掛

better-scroll是一個為行動端各種捲動場景提供絲滑的捲動效果的外掛,如果在vue中使用可以參考作者的文章當 better-scroll 遇見 Vue

swiper是一個輪播圖外掛,如果是在vue中使用可以直接使用vue-awesome-swipervue-awesome-swiper基於Swiper4,並且支援SSR。

【相關推薦:、】

以上就是移動web開發能用vue嗎的詳細內容,更多請關注TW511.COM其它相關文章!