使用 vue 開發過程中遇到的問題或知識點總結,持續更新中…
最近更新:2019-11-29
1.國際化
國際化外掛:vue-i18n
2.強制換行與禁止換行
讓多行內容顯示一行,多餘的用...表示
white-space : nowrap
overflow: hidden
text-overflow : ellipsis
複製程式碼
內容超過寬度時強制換行
overflow: hidden;
word-wrap:break-word;
overflow-wrap: break-word;
複製程式碼
注:CSS3中將 <' word-wrap '> 改名為 <' overflow-wrap '>,用時最好兩個都寫上
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%
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)
}
複製程式碼
使用
let date = new Date(timestamp)
let fmtDate = formatDatetime(date, 'yyyy-MM-dd hh:mm')
複製程式碼
也可以使用第三方的庫: moment.js
、dayjs
5.給元件繫結原生事件
<custom @click.native='handleClick'></custom>
複製程式碼
只需要在@click
後面加上.native
就可以直接處理原生點選事件了
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-class
和 leave-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>
上新增 appear
和 appear-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-class
和 leave-active-class
加上相應的類名 fade-enter-active
和 fade-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與安卓雙向通訊的文章:
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
需要兩步:
-
安裝依賴
npm install sass-resources-loader 複製程式碼
-
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>
複製程式碼
重點:
-
想要自動換行,通過以下三行程式碼實現:
display: flex; flex-direction: row; flex-wrap: wrap; 複製程式碼
-
每行幾個圖示,通過 item 的寬度控制。如果每行四個圖示,那 item 的寬度就是 25%,如果每行5個圖示,那每個 item 的寬度就是 20%.
19. 超出寬度橫向滑動
當子元件的寬度超過父元件,實現橫向滑動。
父元件可以是整個螢幕的根元素,也可以是某個特定的元素。只要設定好 css 即可。
設父元素的 class=parent
,子元素的 class=child
.parent{
//其他樣式省略,只列出控制橫向滑動必須的程式碼
display: flex;
overflow-x: auto;
overflow-y: hidden;
.child{
// 其他樣式省略,只列出控制橫向滑動必須的程式碼
//這句話的意思是不會被壓縮大小
flex-shrink: 0;
}
}
複製程式碼
在你的 css 程式碼中加上這幾行,就可以實現橫向滑動啦。
20. 只顯示 n 行,多餘的用省略號表示
經常有需求是隻顯示兩行或三行,多餘的用省略號表示。
適用範圍:
因使用了WebKit的CSS擴充套件屬性,該方法適用於WebKit瀏覽器及移動端;
注:
-webkit-line-clamp用來限制在一個塊元素顯示的文字的行數。 為了實現該效果,它需要組合其他的WebKit屬性。
常見結合屬性:
display: -webkit-box: 必須結合的屬性 ,將物件作為彈性伸縮盒子模型顯示。
-webkit-box-orient: 必須結合的屬性,設定或檢索伸縮盒物件的子元素的排列方式。
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
複製程式碼
21. flex 佈局中,單個元素靠右對齊
如下圖,姓名、性別、評論圖示這一行有三個元素,是 flex 佈局,前兩個元素靠左,評論圖示靠右。
已知父元素的佈局為
display: flex;
flex-direction: row;
align-items: center;
複製程式碼
實現起來有三種方法:
- 給姓名和性別兩個元素再加一層 div, 並把這個 div 設定
flex: 1
。缺點是多了層巢狀,有點麻煩。 - 給評論圖示這個元素設定
flex: 1; text-align: right; 複製程式碼
- 給評論圖示這個元素設定
margin-left: auto; 複製程式碼
後兩種方法都比較簡單,推薦。