使用 vue 開發過程當中遇到的問題或知識點總結,持續更新中…css
最近更新:2019-06-13html
國際化插件:vue-i18nvue
讓多行內容顯示一行,多餘的用...表示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
<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
/** * 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.js
、dayjs
npm
<custom @click.native='handleClick'></custom>
複製代碼
只須要在@click
後面加上.native
就能夠直接處理原生點擊事件了json
props
傳值<custom content="hello world"></custom>
複製代碼
emit
發送事件this.$emit('chooseType', type)
複製代碼
父組件接收事件:
<custom content="hello world" @chooseType="handleType"></custom>
複製代碼
主要經過事件總線傳值
在根節點給 Vue
掛載一個空的 Vue
對象
Vue.prototype.bus = new Vue();
複製代碼
須要發送事件的組件裏
this.bus.$emit("change", params)
複製代碼
接收事件的組件
this.bus.$on("change", (msg) => {
//do yourself work
})
複製代碼
動態切換顯示的組件
<component :is='type'></component>
data(){
components:{
component-one,
component-two
}
return{
type: 'component-one'
}
}
複製代碼
<component>
是vue官方提供的標籤,經過更改 is
指向的子組件名來動態切換組件。
只渲染元素和組件一次。隨後的從新渲染,元素/組件及其全部的子節點將被視爲靜態內容並跳過。這能夠用於優化更新性能。
<!-- 單個元素 -->
<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>
複製代碼
.fade-enter-active, .fade-leave-active{
transition: opacity 2s
}
.fade-enter, .fade-leave-to{
opacity: 0
}
複製代碼
//引入 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
便可。
<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}"
複製代碼
<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"
:先進後出
使用 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>
複製代碼
路徑前加 require()
<img :src="bookingManageImg" slot="icon"/>
bookingManageImg(){
return this.selectedTab === "bookingManage" ? require('../assets/manage_focus.png') : require('../assets/manage_normal.png')
},
複製代碼
若是在循環裏還直接用 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>
複製代碼
刷新頁面後,存在 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
}
}
}
複製代碼
詳細解析見文章:Vue 返回記住滾動條位置詳解
首先在 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();
})
複製代碼
先安裝 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
同級。
我有一篇專門講解vue與安卓雙向通訊的文章:
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 聲明的變量啦。
官方是不推薦子組件直接改變父組件傳遞過來的屬性的,若是你這麼作了,會有警告。
但有時的確是須要在子組件中改變父組件的屬性,由於省事啊……好比子組件中有 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
屬性。這樣就能夠經過子組件直接改變父組件的值了。
實現相似的九宮格代碼:
<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%.