Vue 開發經驗小記(持續更新)

使用 vue 開發過程當中遇到的問題或知識點總結,持續更新中…css

最近更新:2019-06-13html

1.國際化

國際化插件:vue-i18nvue

2.強制換行與禁止換行

讓多行內容顯示一行,多餘的用...表示webpack

white-space : nowrap
overflow: hidden
text-overflow : ellipsis
複製代碼

內容超過寬度時強制換行git

overflow: hidden;
word-wrap:break-word;
overflow-wrap: break-word;
複製代碼

注:CSS3中將 <' word-wrap '> 更名爲 <' overflow-wrap '>,用時最好兩個都寫上github

3.顯示寬高相等的圖片,寬度爲屏幕寬度,高度與寬度相等

<div class="image-header">
  <img :src="food.image"/>
</div>

.image-header
    position: relative
    width:100%
    height: 0
    padding-top : 100%
    img
        position: absolute
        left: 0
        top: 0
        width: 100%
        height: 100%
複製代碼

重點是父元素的height設爲0,padding-top設爲100%web

4.轉換時間的工具類

/** * Created by solo on 2018/6/6. */

export function formatDatetime(date, fmt) {
  if(/(y+)/.test(fmt)){
    fmt = fmt.replace(RegExp.$1, (date.getFullYear()+"").substr(4-RegExp.$1.length))
  }

  let obj = {
    "M+": date.getMonth() + 1,
    "d+": date.getDay(),
    "h+": date.getHours(),
    "m+": date.getMinutes(),
    "s+": date.getSeconds()
  }

  for(let key in obj){
    if(new RegExp(`(${key})`).test(fmt)){
      let str = obj[key] + ''
      fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : padLeftZero(str))
    }
  }

  return fmt

}


function padLeftZero(str) {
  return ("00" + str).substr(str.length)
}
複製代碼

使用vuex

let date = new Date(timestamp)
let fmtDate =  formatDatetime(date, 'yyyy-MM-dd hh:mm')
複製代碼

也可使用第三方的庫: moment.jsdayjsnpm

5.給組件綁定原生事件

<custom @click.native='handleClick'></custom>
複製代碼

只須要在@click後面加上.native就能夠直接處理原生點擊事件了json

6. vue中組件間傳值

6.1 父子組件間傳值

  • 父組件給子組件傳值,直接經過props傳值
<custom content="hello world"></custom>
複製代碼
  • 子組件給父組件傳值,經過 emit發送事件
this.$emit('chooseType', type)
複製代碼

父組件接收事件:

<custom content="hello world" @chooseType="handleType"></custom>
複製代碼

6.2 非父子組件傳值

主要經過事件總線傳值

在根節點給 Vue 掛載一個空的 Vue 對象

Vue.prototype.bus = new Vue();
複製代碼

須要發送事件的組件裏

this.bus.$emit("change", params)
複製代碼

接收事件的組件

this.bus.$on("change", (msg) => {
    //do yourself work
})
複製代碼

7. 動態組件

動態切換顯示的組件

<component :is='type'></component>

data(){
	components:{
        component-one,
        component-two
	}
    return{
        type: 'component-one'
    }
}
複製代碼

<component> 是vue官方提供的標籤,經過更改 is 指向的子組件名來動態切換組件。

8. v-once 指令

只渲染元素和組件一次。隨後的從新渲染,元素/組件及其全部的子節點將被視爲靜態內容並跳過。這能夠用於優化更新性能。

<!-- 單個元素 -->
<span v-once>This will never change: {{msg}}</span>
<!-- 有子元素 -->
<div v-once>
  <h1>comment</h1>
  <p>{{msg}}</p>
</div>
<!-- 組件 -->
<my-component v-once :comment="msg"></my-component>
<!-- `v-for` 指令-->
<ul>
  <li v-for="i in list" v-once>{{i}}</li>
</ul>
複製代碼

9.過渡和動畫

9.1 過渡

.fade-enter-active, .fade-leave-active{
	transition: opacity 2s
}
.fade-enter, .fade-leave-to{
	opacity: 0
}
複製代碼

9.2 動畫結合 Animate.css

//引入 animate.css
<link rel="stylesheet" type="text/css" href="animate.css">

//佈局
<transition enter-active-class="animated bounce" leave-active-class="animated shake">
	<p v-if="show">hello world</p>
</transition>
<button @click='toggleShow'>toggle</button>
複製代碼

要定義 enter-active-classleave-active-class 的類名,且必須有 animated,想要什麼動畫效果就寫在第二個位置上

解決第一次顯示沒有動畫的bug

<transition 
	appear 
	enter-active-class="animated bounce" 
	leave-active-class="animated shake" 
	appear-active-class="animated bounce">
	<p v-if="show">hello world</p>
</transition>
複製代碼

<transition> 上添加 appearappear-active-class 便可。

9.3 同時使用過渡和動畫

<transition 
    name="fade"
    type='transition'
    appear 
    enter-active-class="animated bounce fade-enter-active" 
    leave-active-class="animated shake fade-leave-active" 
    appear-active-class="animated bounce">
    <p v-if="show">hello world</p>
</transition>
複製代碼

enter-active-classleave-active-class 加上相應的類名 fade-enter-activefade-leave-active ,而後在樣式中定義過渡效果便可。

.fade-enter-active, .fade-leave-active{
	transition: opacity 2s
}
.fade-enter, .fade-leave-to{
	opacity: 0
}
複製代碼

動畫執行的總時長是根據動畫仍是過渡來定呢?能夠手動指定:

//指定總體動畫時間爲過渡動畫時間
type='transition'
複製代碼

還能夠本身指定動畫總時長:

//指定動畫時長爲10秒
:duration="10000"

//分別指定進場時長5秒和出場動畫時長10秒
:duration="{enter: 5000, leave: 10000}"
複製代碼

9.4 多個組件和元素的過渡

  • 多個元素過渡
<div id="app">
	<transition name="fade" mode="out-in">
		<div v-if="show" key="hello">Hello world</div>
		<div v-else key="bye">Bye world</div>
	</transition>
	<button @click="toggleShow">Add</button>
</div>
複製代碼

須要給元素加 key, 防止vue複用元素致使沒有動畫效果。

能夠指定切換模式,mode="out-in":先出後進,mode="in-out":先進後出

  • 多個組件過渡跟多個元素過渡相似

9.5 vue中列表過渡

使用 transition-group 屬性

<div id="app">
	<transition-group name="fade">
		<div v-for="item in list" :key="item.id">
			{{item.title}}
		</div>
	</transition-group>
	<button @click="add2List">Add</button>
</div>


<style type="text/css" >
	.fade-enter-active, .fade-leave-active{
		transition: opacity 2s
	}
	.fade-enter, .fade-leave-to{
		opacity: 0
	}
</style>
複製代碼

10. img 標籤的 src 動態綁定

1)路徑固定的圖片

路徑前加 require()

<img :src="bookingManageImg" slot="icon"/>

bookingManageImg(){
    return this.selectedTab === "bookingManage" ? 	require('../assets/manage_focus.png') : require('../assets/manage_normal.png')
},
複製代碼

2)for 循環裏圖片的路徑不固定

若是在循環裏還直接用 require() 的話,webpack 會將圖片來當作模塊來用,由於是動態加載的,因此 url-loader 將沒法解析圖片地址,因此會報錯找不到模塊。

解決辦法是採用拼接的方式: require('../assets/icons/' + item.icon + '.png'),對象裏只存圖片的名字,圖片路徑是固定的,因此直接用字符串寫上去。

list 的數據格式:

const list = [
    {
      name: "美食",
      icon: "food"
    },
    {
      name: "電影",
      icon: "movie"
    },
]
複製代碼

佈局文件:

<div class="item" v-for="item in list">
  <img :src="require('../assets/icons/' + item.icon + '.png')" class="icon">
  <div class="name">{{item.name}}</div>
</div>
複製代碼

11. vuex 在頁面刷新後狀態丟失解決辦法

刷新頁面後,存在 vuex 的數據會丟失,給調試帶來不便。把用戶的登陸信息放到 sessionStorage 中避免丟失。

const USER_INFO = "userInfo";

export default new Vuex.Store({
  state: {
    userInfo: JSON.parse(sessionStorage.getItem(USER_INFO))
  },
  mutations: {
    setUserInfo(state, userInfo){
      //存儲到 sessionStorage 中以防刷新頁面後狀態丟失
      sessionStorage.setItem(USER_INFO, JSON.stringify(userInfo));
      state.userInfo = userInfo
    }
  }
}
複製代碼

12. 返回記住滾動條位置

詳細解析見文章:Vue 返回記住滾動條位置詳解

13. 修改頁面 Title

首先在 router.js 裏,每一個路由加上 meta ,設置 title

routes: [
  {
    path: '/login',
    name: 'login',
    component: Login,
    meta:{
      title:'登陸'
    }
  },
  {
    path: '/home',
    name: 'home',
    component: Home,
    children: [],
    meta:{
      title:'主頁'
    }
  }
]
複製代碼

而後在 main.js 裏經過前置路由動態修改 title

router.beforeEach((to, from, next) => {
  /* 路由發生變化修改頁面title */
  if (to.meta.title) {
    document.title = to.meta.title;
  }
  next();
})
複製代碼

14. 打包時啓用 Gzip 壓縮

先安裝 webpack 插件

npm install --save-dev compression-webpack-plugin
複製代碼

再在 vue.config.js 裏添加以下代碼:

const CompressionPlugin = require("compression-webpack-plugin")

module.exports = {

  // 基本路徑
  baseUrl: './',
  // 輸出文件目錄
  outputDir: 'dist',
  // 啓用 Gzip 壓縮
	configureWebpack: () => {
    module.exports = {
      configureWebpack:config=>{
        if(progress.env.NODE_ENV === 'production'){
          return{
            plugins: [

              new CompressionPlugin({
                test:/\.js$|\.html$|.\css/, //匹配文件名
                threshold: 10240,//對超過10k的數據壓縮
                deleteOriginalAssets: false //不刪除源文件
              })
            ]
          }
        }
      },
    }
  },
}
複製代碼

Vue CLI 3 默認沒有 vue.config.js ,在根目錄新建一個就好,位置跟 package.json 同級。

15. vue 與 安卓原生應用通訊

我有一篇專門講解vue與安卓雙向通訊的文章:

Android webview 與 js(Vue) 交互

16. 如何在樣式中使用 scss 的聲明的全局變量

sass 聲明的變量如:

$color-primary: #409EFF;
$color-success: #67C23A;
$color-warning: #E6A23C;
$color-danger: #F56C6C;
$color-info: #909399;
複製代碼

普通的引用方法爲

<style scoped lang="scss">
  @import "../../public/css/index";
  .home {
    color: $color-primary;
  }
</style>
複製代碼

須要先在要使用的文件中引入聲明的文件,而後才能使用。

這樣比較麻煩,代碼冗餘。可使用更優雅的方式:sass-resources-loader

使用 sass-resources-loader 須要兩步:

  1. 安裝依賴

    npm install sass-resources-loader
    複製代碼
  2. vue.config.js 裏配置。

    這裏使用的是 Vue-CLI 3. 將代碼中的 resources 路徑換成本身的路徑便可。

    // vue.config.js
    module.exports = {
      chainWebpack: config => {
        const oneOfsMap = config.module.rule('scss').oneOfs.store
        oneOfsMap.forEach(item => {
          item
            .use('sass-resources-loader')
            .loader('sass-resources-loader')
            .options({
              // Provide path to the file with resources
              resources: './path/to/resources.scss',
    
              // Or array of paths
              resources: ['./path/to/vars.scss', './path/to/mixins.scss']
            })
            .end()
        })
      }
    }
    複製代碼

其餘環境的詳細配置說明見 sass-resources-loader 官網

配置完以後,就能夠在任意文件裏使用 sass 聲明的變量啦。

17. 子組件中改變父組件經過 props 傳遞過來的屬性

官方是不推薦子組件直接改變父組件傳遞過來的屬性的,若是你這麼作了,會有警告。

但有時的確是須要在子組件中改變父組件的屬性,由於省事啊……好比子組件中有 Dialog,Dialog 的顯示與隱藏要經過父組件控制,同時子組件關閉了 Dialog 要同步更新父組件中屬性值。

固然有不少 "正確" 的方式能夠作到,好比 vuex,好比用父子組件的通訊,子組件改變值了發個通知通知父組件更新對應的值。

可是,上面兩種方法都比較麻煩。我就想在父組件中給子組件傳遞個變量,子組件改變它的值了,父組件中的變量也會自動更新。

這就用到一個 "漏洞",把要傳遞的值封裝成一個對象,改變對象中的屬性值,就不會出現警告。由於對象仍是原來的對象,只是裏面的值變了。

父組件以下。注意 data 中的 visible: {value: false} 是個對象,不能寫成 visible: false,會出現警告。

<template>
  <child :visible="visible"/>
</template>

<script>
  export default {
    components: {
    	child
    },
    data(){
    	return{
    		visible: {value: false}
    	}
    }
  }
</script>
複製代碼

子組件以下:

<el-dialog :visible.sync="visible.value">
複製代碼

當子組件改變值時改變的是 visible 對象中的 value 屬性。這樣就能夠經過子組件直接改變父組件的值了。

18. 九宮格的實現

實現相似的九宮格代碼:

<template>
  <div class="view-home">
    <div class="category-wrapper">
      <div class="category-name">分類一</div>
      <div class="icons">
        <div class="item" v-for="item in list">
          <img :src="require('../assets/icons/' + item.icon + '.png')" class="icon">
          <div class="name">{{item.name}}</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>

  const LIST = [
    {name: "電影",icon: "movie"},
    {name: "美食",icon: "food"},
    {name: "美髮",icon: "hair"},
    {name: "周邊遊",icon: "around"},
    {name: "酒店",icon: "hotel"},
    {name: '代購',con: "dg"}
  ];

  export default {
    components: {},
    data() {
      return {
        list: ICON_LIST,
      }
    },
  }
</script>

<style scoped lang="scss">
  .view-home {
    display: flex;
    flex-direction: column;
    width: 100%;
    padding: px2rem(10);
    box-sizing: border-box;

    .category-wrapper {
      width: 100%;
      display: flex;
      flex-direction: column;
      background-color: white;

      .category-name {
        font-size: $font-size-normal;
        color: $text-main;
        padding: px2rem(12);
        border-bottom: px2rem(1) solid $border-third;
      }

      .icons {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;

        .item {
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
          width: 25%;
          padding: px2rem(10) 0;

          .icon {
            width: px2rem(40);
            height: px2rem(40);
          }

          .name {
            font-size: $font-size-small;
            color: $text-normal;
            margin-top: px2rem(10);
          }
        }
      }
    }
  }
</style>

複製代碼

重點:

  1. 想要自動換行,經過如下三行代碼實現:

    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    複製代碼
  2. 每行幾個圖標,經過 item 的寬度控制。若是每行四個圖標,那 item 的寬度就是 25%,若是每行5個圖標,那每一個 item 的寬度就是 20%.

相關文章
相關標籤/搜索