Router Parameter Passing Between List and Detail Pages
When navigating from a product list page to a detail page, passing a product ID is essential:
<router-link :to="{path: 'detail', query: {productId: 1}}">View Details</router-link>
The resulting URL becomes http://localhost:8080/#/detail?productId=1, with the parameter persisting even after page refresh. Access the parameter using this.$route.query.productId.
Vue offers two parameter passing methods: query parameters and params with dynamic routes.
Key Differences:
- Route Navigasion: Query uses path, params uses name
<!-- Query with path -->
<router-link :to="{path: 'Detail', query: { id: 1 }}">Detail</router-link>
<!-- Params with name -->
<router-link :to="{name: 'Detail', params: { id: 1 }}">Detail</router-link>
- Parameter Reception: Query via
this.$route.query, params viathis.$route.params
// Query parameters
created() {
const productId = this.$route.query.id;
}
// Params parameters
created() {
const itemId = this.$route.params.id;
}
-
URL Format: Query appears as
/detail?productId=1&user=123, while params with dynamic routes shows as/detail/123 -
Route Definition Requirement: Params with dynamic routes must be defined in the route configuration:
{
path: '/detail/:id',
name: 'Detail',
component: Detail
}
Undefined params parameters will be lost upon page refresh, making them unreliable for operations requiring persistent parameters.
Cross-Origin API Requests in Development
Browser security policies often block cross-origin requests during development. Configure webpack dev server proxy to resolve this:
// webpack.config.js or vue.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
}
Restart the development server after configuration. Set axios base URL to simplify API calls:
axios.defaults.baseURL = '/api';
UI Library On-Demand Loading
Reduce bundle size by importing only necessary components:
npm install vant -S
npm install babel-plugin-import -D
Configure Babel (.babelrc):
{
"plugins": [
["import", {
"libraryName": "vant",
"libraryDirectory": "es",
"style": true
}]
]
}
Component usage:
import { Button, List } from 'vant';
Vue.use(Button).use(List);
Scoped Style Overrides for UI Components
Use deep selectors to modify third-party component styles within scoped CSS:
/* For LESS/SASS */
.van-tabs /deep/ .van-ellipsis {
color: blue;
}
/* For plain CSS */
.van-tabs >>> .van-ellipsis {
color: blue;
}
Timer Management
Prevent memory leaks by properly cleaning up timers:
export default {
data() {
return {
intervalId: null
}
},
mounted() {
this.intervalId = setInterval(() => {
console.log('Timer running');
}, 1000);
// Auto-cleanup on component destruction
this.$once('hook:beforeDestroy', () => {
clearInterval(this.intervalId);
});
},
beforeDestroy() {
clearInterval(this.intervalId);
}
}
Mobile Responsive Adaptation
Create rem.js for responsive scaling:
(function(win, doc) {
const docEl = doc.documentElement;
const resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize';
const recalc = function() {
const clientWidth = docEl.clientWidth;
docEl.style.fontSize = (clientWidth >= 750) ? '100px' : 100 * (clientWidth / 750) + 'px';
};
recalc();
win.addEventListener(resizeEvt, recalc, false);
})(window, document);
Import in main.js: import './config/rem'
Advanced Carousel with Vue-Awesome-Swiper
For complex carousel requirements beyond basic UI libraries:
npm install vue-awesome-swiper --save
Component implementation:
<template>
<swiper :options="carouselOptions" ref="myCarousel">
<swiper-slide><div class="slide-item">Slide 1</div></swiper-slide>
<swiper-slide><div class="slide-item">Slide 2</div></swiper-slide>
<div class="swiper-pagination" slot="pagination"></div>
</swiper>
</template>
<script>
import 'swiper/dist/css/swiper.css';
import { swiper, swiperSlide } from 'vue-awesome-swiper';
export default {
components: { swiper, swiperSlide },
data() {
return {
carouselOptions: {
pagination: { el: '.swiper-pagination' },
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
}
}
}
}
}
</script>
Production Build Optimization
Disable source maps in production:
// config/index.js or vue.config.js
module.exports = {
productionSourceMap: false
}
Remove 300ms touch delay on mobile:
npm install fastclick -S
import FastClick from 'fastclick';
FastClick.attach(document.body);
Component Option Organization
Maintain consistent option ordering for better readability:
- Side Effects:
el - Global Awareness:
name,parent - Component Type:
functional - Template Modifiers:
delimiters,comments - Template Dependencies:
components,directives,filters - Composition:
extends,mixins - Interface:
inheritAttrs,model,props/propsData - Local State:
data,computed - Events:
watch, lifecycle hooks - Non-reactive Properties:
methods - Rendering:
template/render,renderError
Bundle Analysis
Visualize bundle composition:
npm run build --report
Route Lazy Loading
Improve initial load performance:
const ProductDetail = () => import('@/views/ProductDetail.vue');
export default new Router({
routes: [{
path: '/product/:id',
component: ProductDetail
}]
});
Gzip Compression
Enable production gzip compression:
npm install compression-webpack-plugin@1.1.11 -D
// config/index.js
build: {
productionGzip: true
}
Scoped CSS and Deep Selectors
Scoped CSS adds data attributes to selectors. Use deep selectors for child component styling:
.parent-component >>> .child-element {
margin: 10px;
}
/* For preprocessors */
.parent-component /deep/ .child-element {
margin: 10px;
}
Performance Monitoring with Hiper
Install global performance tool:
npm install hiper -g
Usage examples:
hiper example.com
hiper -n 100 "example.com?param=value"
hiper -n 50 "example.com" --no-cache
Data Fetching Strategies
Post-Navigation Fetching (with loading states)
<template>
<div class="page-container">
<loading-spinner v-if="isLoading" />
<error-display v-else-if="hasError" />
<page-content v-else-if="dataLoaded" :content="pageData" />
<empty-state v-else />
</div>
</template>
<script>
export default {
data() {
return {
isLoading: true,
hasError: false,
dataLoaded: false,
pageData: null
}
},
async created() {
try {
this.pageData = await this.fetchData();
this.dataLoaded = true;
} catch (error) {
this.hasError = true;
} finally {
this.isLoading = false;
}
}
}
</script>
Pre-Navigation Fetching
export default {
beforeRouteEnter(to, from, next) {
api.fetchProductDetail(to.params.id).then(response => {
next(vm => {
vm.productInfo = response.data;
vm.loadComplete = true;
});
});
}
};
Custom Component Two-Way Binding
Implement v-model for custom components:
<!-- Parent component -->
<custom-modal v-model="modalVisible"></custom-modal>
<!-- Child component -->
<template>
<div class="modal" v-show="internalValue">
<button @click="closeModal">Close</button>
</div>
</template>
<script>
export default {
model: {
prop: 'visible',
event: 'visibility-change'
},
props: {
visible: {
type: Boolean,
default: false
}
},
computed: {
internalValue: {
get() { return this.visible; },
set(value) { this.$emit('visibility-change', value); }
}
},
methods: {
closeModal() {
this.internalValue = false;
}
}
};
</script>
Route Module Organization
Split routes by feature modules:
// router/index.js
import Vue from 'vue';
import Router from 'vue-router';
import productRoutes from './modules/products';
import userRoutes from './modules/users';
Vue.use(Router);
export default new Router({
routes: [
...productRoutes,
...userRoutes
]
});
// router/modules/products.js
export default [
{
path: '/products',
component: () => import('@/views/Products.vue'),
meta: { title: 'Products' }
}
];
Shared Utility Mixins
Create reusable functionality with mixins:
// mixins/formatting.js
import { formatCurrency, formatDate } from '@/utils/helpers';
export default {
filters: {
mixinCurrency(value) {
return formatCurrency(value);
},
mixinShortDate(value) {
return formatDate(value, 'short');
}
}
};
// Component usage
import formattingMixin from '@/mixins/formatting';
export default {
mixins: [formattingMixin]
};
Asset Path Configuration
Configure build paths for proper asset resolution:
// config/index.js
module.exports = {
build: {
assetsPublicPath: './'
}
};
// Build utility for CSS background paths
// build/utils.js
cssLoader: {
loader: 'css-loader',
options: {
sourceMap: options.sourceMap
}
}