目录
vue打包路径问题/build不在服务器中打开空白/cordova打开为空白
缓存/keep-alive/对router使用keep-alive
加上position:absolute后,动画执行过程中抖动。
FAQ
资源
vueApi https://cn.vuejs.org/v2/api/
vue指导 https://cn.vuejs.org/v2/guide/
devTools调试 https://github.com/vuejs/vue-devtools
router路由 https://router.vuejs.org/zh/
vuex https://vuex.vuejs.org/zh/
srr服务器渲染 https://ssr.vuejs.org/zh/
初始化工程
//vue-cli是2.X版本
npm install -g vue-cli
vue init webpack
工程目录
目录"store"为Vuex相关的文件
ie兼容包
npm i -s 'babel-polyfill'
import "babel-polyfill";------>注意import位置尽量靠前,必须vuex前面
webpack打包img
//把图片包含进来
import png1 from '@/assets/666320.png';
import png2 from '@/assets/6pro320-220.png';
import png3 from '@/assets/pc-320-220-mi8se.png';
import png4 from '@/assets/ds50.png';
import png5 from '@/assets/ds320_220.png';
//使用
{
shopname: "手机",
list:[
png4,
png5,
]
},
定义组件过滤器
filters: {
numFilter(value) {
// 截取当前数据到小数点后三位
let transformVal = Number(value).toFixed(3)
let realVal = transformVal.substring(0, transformVal.length - 1)
// num.toFixed(3)获取的是字符串
return Number(realVal)
}
}
全局过滤器和加载
过滤器定义"./filter/custom.js"
function numFilter(value) {
// 截取当前数据到小数点后三位
let transformVal = Number(value).toFixed(3)
let realVal = transformVal.substring(0, transformVal.length - 1)
// num.toFixed(3)获取的是字符串
return Number(realVal)
}
/**
*
* @param {*} Vue
* @param {*} custom
*/
function init(Vue){
Object.keys(this).forEach(key => {
if(key!=='init') {
Vue.filter(key, this[key]);
// console.log(key,custom[key])
}
})
}
export {numFilter ,init}
加载、使用"main.js"
import * as custom from './filters/custom'
custom.init(Vue);//加载过滤器
深度监听/对象以及内部属性的监听
深度监听
watch: {
obj: {
handler(newName, oldName) {
console.log('obj.a changed');
},
immediate: true,
deep: true
}
}
第一个handler:其值是一个回调函数。即监听到变化时应该执行的函数。
第二个是deep:其值是true或false;确认是否深入监听。(一般监听时是不能监听到对象属性值的变化的,数组的值变化可以听到。)
第三个是immediate:其值是true或false;确认是否以当前的初始值执行handler的函数。
改变数组的值
var target = {};
Object.assign(target,item,{checked:val})
this.$set(this.list, index, target);
常见事件监听
@click | @change 当前元素失去焦点并且元素的内容发生改变而触发此事件 | @blur | @focus
原生事件监听
@click.native | @mouseenter.native | @dbclick.native 。。。mousedown mouseup mouseover mouseout
路由器简单使用
./router/index.js
import Vue from 'vue'
import Router from 'vue-router'
// import HelloWorld from '@/components/HelloWorld'
import index from '@/views/index'
// import Code404 from '@/components/Code404'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
// name: 'index',
component: index
},
{
path: '*',
// name: 'index',
redirect: '/'
// component: Code404
}
]
})
main.js
import router from './router'
//放入根vue
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
嵌套路由的使用/二级页问题
// router/index.js
import Index from '@/views/index'
import MainPage from '@/views/MainPage'
import My from '@/views/my'
import Order from '@/views/order'
import ClasstifyAll from '@/views/ClasstifyAll'
import Search from '@/views/search'
import url from '../global/url'
let nav = url.navigator;
export default new Router({
routes: [
{
path: '/',
// name: 'HelloWorld',
redirect:'/mainpage/index'
},
/**
* mainpage页,主页
*/
{
path: nav.mainPage.selfpath,
name: 'MainPage',
component: MainPage,
children:[
{
path: nav.mainPage.children.indexPath,
name: 'index',
component: Index
},
{
path: nav.mainPage.children.myPath,
name: 'my',
component: My
},
{
path: nav.mainPage.children.orderPath,
name: 'order',
component: Order
}
]
},
/**
* classtifyAll页,全部分类页
*/
{
path: nav.classtifyAll,
name: 'classtifyAll',
component: ClasstifyAll,
},
{
path: nav.searchPath,
name: 'Search',
component: Search,
}
]
})
主页中的子分页(index、my、order等)需要以子页形式存在,二级页是跟主页mainpage同级的,这样在主页子分页中点击了二级页链接,才能使得二级页全屏。
组件定义.vue文件
<template>
<div class="root">
</div>
</template>
<script>
export default {
props:['itemObj'],
data() {
return {
maxNum:99,
};
},
methods:{
del(){
this.list.splice(this.index,1);
},
},
computed: {
totalPrice() {
return this.itemObj.num * this.itemObj.price;
}
},
watch:{
// checked:function(val){
// }
},
filters: {
}
};
</script>
<style scoped>
.root{
display: flex;
width: 1200px;
/* background-color: #234566; */
color: #000;
font-size: 12px;
padding: 10px;
border: 1px solid #ddd;
}
</style>
组件注册
全局注册
Vue.component('my-component-name', {
// ... 选项 ...
})
局部注册
import ComponentA from '@/components/ComponentA.js'
//或者
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
import路径中包含的 "@"
例如:"@/components/xxx.js" @在webpack中有定义,表示src目录
组件prop双向绑定
第一种方式/自定义事件
父组件中
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
子组件中
this.$emit('update:title', newTitle)
第二种方式/.sync修饰符
父组件中
<XXX v-bind:showFlag.sync="showFlag" >
子组件中
this.$emit('update:showFlag', false);
关闭eslint代码检测
在config/index.js目录下
// useEslint: true,
useEslint: false,
绑定Style中带有图片/图片访问不到
//使用require或者import导入,只有这样,webpack打包才会导入图片,不然会出现图片访问不到
return {
backgroundImage:'url(' + require('../../assets/2.jpg') + ')',
backgroundPosition:this.bigDivx+'%' +' '+this.bigDivy+'%'
}
属性有多个属性值
// 空格隔开
backgroundPosition:this.bigDivx+'%' +' '+this.bigDivy+'%'
绑定style
<div class="zhezhao" :style="jisuanzuobiao" v-show="zhezhaoShow" ></div>
computed:{
jisuanzuobiao(){
let min = 0;
let max = 500;
let zhezhaoY = this.bianjie(this.zhezhaoY);
let zhezhaoX = this.bianjie(this.zhezhaoX);
return {top:zhezhaoY+'px', left:zhezhaoX+'px'}
}
}
访问根实例vue/$root
通过this.$root
1.可以作为全局的store使用,放入共享的数据
2.全局bus,自定义事件监听和注册,达到各个组件间的通信
自定义事件在程序中监听/组件间的通行
$emit ("eventName",params) 发送一个事件
$on(eventName, eventHandler) 侦听一个事件
$once(eventName, eventHandler) 一次性侦听一个事件
$off(eventName, eventHandler) 停止侦听一个事件
通过根vue完成通信操作(this.$root),
vue打包路径问题/build不在服务器中打开空白/cordova打开为空白
config/index.js文件修改一下位置
vue中使用scss、sass
npm install node-sass --save-dev //只需要这句
npm install sass-loader --save-dev
<style lang="scss" scoped>
屏幕适配问题/设计稿宽计算
//在需要使用的文件import 'vw_base.js'
//375为设计稿宽,一般宽为750,可以改成实际设计稿宽
$vm_base: 375;
@function vw($px) {
@return ($px / 375) * 100vw;
}
阿里图标库
在main.js中引入iconfont.css样式
import 'xxx/xxx/xxx/iconfont.css'
vscodeTab键不生效/emmet
文件-首选项-设置
v1.5版本后配置如下
"emmet.triggerExpansionOnTab": true,
"emmet.includeLanguages": {
"vue-html": "html",
"vue": "html"
}
设置代码
"emmet.syntaxProfiles": {
"vue-html": "html",
"vue": "html"
}
操作dom/获取到的数据不正确/$nextTick()
修改data中的数据,再到dom中获取。这时候可能获取到数据为上一次的数据,dom还没有完成刷新。使用this.$nextTick(funtion(){})
返回上一页
$router.go(-1)
各种数据url链接/路由跳转路径path/全局访问
1写入一个文件中统一管理
2写入在根vue中,统一'this.$url'调用,
3或者在main.js中 "var url = 导入的url" 变为全局
//global/url.js
var url = {
index: '/data/index',
indexSwiper: '/data/indexSwiper',
indexClass1: '/data/indexClass1',
indexClass2: '/data/indexClass2',
listing: '/data/listing',
/**
* 导航路径
*/
navigator: {
mainPage: {
selfpath: '/mainpage',
children:{
indexPath: 'index',
indexFullPath:'/mainpage/index',
orderPath: 'order',
orderFullPath:'/mainpage/order',
myPath: 'my',
myFullPath:'/mainpage/my',
}
},
classtifyAll:'/classtifyall',
searchPath:'/search'
}
}
export default url;
局域网访问工程/非本机访问
缓存/keep-alive/对router使用keep-alive
<keep-alive>
<router-view></router-view>
</keep-alive>
缓存滚动的位置/scrollTop
对组件A先使用keep-alive后,在组件A内缓存div滚动位置
<template>
<div class="index-root" id="mainContent">
........
</div>
</template>
data: function() {
return {
offsetTop:0,
};
},
activated() {
// keep-alive组件 页面进入的时候设置滚动高度
document.getElementById("mainContent").scrollTop = this.offsetTop;
},
beforeRouteLeave(to, from, next) {
//组件离开的时候,获取页面滚动高度
this.offsetTop = document.getElementById('mainContent').scrollTop;
next()
},
深度/穿透/子组件样式/deep/>>>
.header{
position: relative;
.mint-header{
height: 16vw;
/deep/ .mintui.mintui-back{ ////完成对子组件中类.mintui.mintui-back穿透
font-size: 6vw;
}
}
组件缓存/keep-alive/路由下的状态保存
注意:对组件A使用时,包含A组件的父B不能保存状态,B被路由替换,则A也是无效的。
app.vue中使用keep-alive包裹router-view
<keep-alive include="mainpage" > //<----------在组件中取名字name='mainpage',这可以激活状态保
存。相对于的不包含属性 exclude=''
<router-view></router-view>
</keep-alive>
router/index.js路由表中
/**
* mainpage页,主页
*/
{
path: nav.mainPage.selfpath,
name: 'mainpage',// 注意<---------App.vue中include='mainpage'不是对应这个name
component: MainPage,
children:[
{
path: nav.mainPage.children.indexPath,
name: 'index',
component: Index
},
{
path: nav.mainPage.children.myPath,
name: 'my',
component: My
},
{
path: nav.mainPage.children.orderPath,
name: 'order',
component: Order
}
]
},
在Mainpage.vue中定义name
export default {
name: 'mainpage',// <-------定义名字与<keep-alive>中include保持一致
data: function() {
return {
nameArray: ["首页", "附近", "发现", "订单", "我的"],
selected: "首页",
// offsetTop:0,
};
},
......
组件全局的自动注册/自动加载
下面代码会自动全局注册'/components'下的组件,
注意:下列代码依赖'lodash'
/**
* 自动全局注册componentS下的组件
*/
import {camelCase,upperFirst} from 'lodash'
import Vue from 'vue';
const requireComponent = require.context(
'@/components', //当前基础组件相对与main.js的相对位置
false, //是否查询子目录
/\.(vue|js)$/
)
requireComponent.keys().forEach(fileName => {
const componentConfig = requireComponent(fileName) //获取组建配置
const componentName =
fileName.replace(/^\.\/(.*)\.\w+$/, '$1') // 剥去文件名开头的 `'./` 和结尾的扩展名
// const componentName = upperFirst( //获取组件的 PascalCase 命名
// camelCase(
// fileName.replace(/^\.\/(.*)\.\w+$/, '$1') // 剥去文件名开头的 `'./` 和结尾的扩展名
// )
// )
console.log(componentName)
// 全局注册组件
Vue.component(
componentName,
componentConfig.default || componentConfig
)
})
返回上一页/回退
<div @click="$router.go(-1)">
<slot></slot>
</div>
全局https网络请求/this.$https调用
import axios from 'axios';
import url from '../global/url'
var https={
listing:{
request(){
return axios.get(url.listing).then((res)=>res.data)
}
},
registerInVue(Vue){
Vue.prototype.$https = https
}
}
export default https;
main.js
/**https访问数据,为index.js文件
* 可以在子vue中通过 this.$url调用
*/
import https from './https/index.js'
https.registerInVue(Vue);
子组件插槽问题?
父中传入插槽所需内容,而内容中,有多个tag需要处理点击事件,但是传入的dom结果作用域是父的,然而需要传入的dom响应子组件内的方法
注意:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。--官网
方式1:个人
mount()方法中,查找(querySelectAll(),)到需要点击事件的node,并对node添加事件
方式2:官网
提示:将子组件作用域方法或值数组传出给父
路由守卫
1.路由器守卫
2.路由全局守卫
3.组件内守卫
4.守卫共享
router/guard.js
import store from '../store/index'
import {Toast} from 'mint-ui'
var guard = {
/**
* user守卫
*/
userGuard:(to, from, next) => {
if(store.getters['user/loginState']){
next();
}else{
Toast({
message: '请先登录',
position: 'bottom',
duration: 3000
});
// next({ path: '/login' })
next(false)
}
}
}
export default guard;
router/index.js
import guard from './guard.js'//------->导入守卫处理函数
export default new Router({
mode:'history',
routes: [
.......
/**
* setting 个人设置页面
*/
{
path:nav.settingPath,
name:"setting",
component:Setting,
beforeEnter: guard.userGuard//------>引用共享函数guard.userGuard
//------>路由器守卫
},
/**
* my-collection 我的收藏页面
*/
{
path:nav.myCollectionPath,
name:"my-collection",
component:MyCollection,
//路由守卫
beforeEnter: guard.userGuard//------>引用共享函数guard.userGuard
},
.......
]
})
跨域
1.找到 vue项目目录 > config > index.js
dev: {
env: require('./dev.env'),
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
'/api': { // 这里的 /api 是固定的
target: 'http://xxxx.cn', //你的服务器地址
changeOrigin: true, //改变源
pathRewrite: {
'^/api': 'http://xxxx.cn' // 意为 用 /api 这个字符代替 后面的地址 在访问接口时直接写 /api ...... 就好了,这个/api可以是任意的字符。
}
}
},
……
}
2.在开发过程中请求数据时直接用 /api (与上面pathRewrite定义的字符保持一致)开头 +后面的接口。
axios.get('/api/xxx.json', function (res) {
console.log(res)
}
异步路由/路由懒加载
以函数返回值形式导入,函数未执行
const Foo = () => import('./Foo.vue')
将导入函数放进router对象,按需求,异步导入执行导入函数
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo }
]
})
把组件按组分块(可不做)
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
注意
如果您使用的是 Babel,你将需要添加 syntax-dynamic-import
(当前新建工程已经存在改插件)插件,才能使 Babel 可以正确地解析语法。
父组件主动获取子组件的数据和方法
1.调用子组件的时候 定义一个ref
<t-tab ref="xxx"></headerchild>//定义的名字xxx,父可以通过xxx调用t-tab
1
2.在父组件里面通过
this.$refs.xxx.属性----------->xxx同上
this.$refs.xxx.方法----------->xxx同上
子组件主动获取父组件的数据和方法在子组件里面通过
this.$parent.属性
this.$parent.方法
子组件无法获取到父传入的props
1.父在mounted()中获取的数据,修改需改绑定在props上的值,
2.错误的原因:子不可以在mounted中去获取,不然报错,因为此时子已经mounted,父的mounted后修改数据在传入晚了。
3.子应该在watch中完成获取数据和操作。
this.$el.offsetHeight获取为0
原因1:当前vue被隐藏v-show=false;,获取为0。所以不能再初始化中运行获取函数。
原因2:v-show=true;需要在$nextTick(function(){})中获取,并且必须重新运行获取函数。
动态加载图片/static
将图片放入static中就行,所有动态图片都可以加载。如果放在assets中,就需要import或者require加载
为路由器加入动画/animate/transition
需要安装animate.css动画库
基本操作
1.html结构
<template>
...
<transition
name="custom-classes-transition" ------------>表示自定义动画
:enter-active-class="transitionInName"------------->表示进入时的动画
:leave-active-class="transitionOutName"------------>表示出去时的动画
>
<keep-alive include="mainpage">
<!-- <keep-alive > -->
<router-view></router-view>
</keep-alive>
</transition>
...
</template>
2.
data() {
return {
transitionInName:'animated slideInRight',
transitionOutName:'animated slideOutLeft'
}
},
。。。。。。。
watch: {
'$route' (to, from) {
if(this.$global.isRouterForward){------------->关键点
//前进动画
this.transitionInName = 'animated slideInRight'
this.transitionOutName = 'animated animated-delay slideOutLeft'
}else{
//回退动画
this.transitionInName = 'animated slideInLeft'
this.transitionOutName = 'animated animated-delay slideOutRight'
}
// 默认为true
this.$global.isRouterForward = true;------------->关键点
}
}
global.js
isRouterForward : true,
back的监听,需要修改标志位isRouterForward =false;表示执行回退动画
this.$global.isRouterForward = false;
this.$router.back()
注意:没有进入动画
因为:进入的组件在出去组件下方,对于手机界面,必然看不见。
.animated{//在
animation-duration: 0.5s;
position:absolute----------->动画不执行、不显示,<transition>加上absolute
}
或者官方解决办法
给<transition>加属性 mode='in-out'。mode='out-in'执行效果难受,先完全出去,在执行进入动画
或者(。。。。。)只要前进时:右侧进入动画,后退时:右侧出去动画
加上position:absolute后,动画执行过程中抖动。
因为在执行动画过程中,父的宽出现的变化。解决:给每一个route(每一页)的根加上定宽。
keep-alive没必要添加include
我以为会出现Android和react那种情况,每次路由push一个页A,就会是一个新的页A,导致栈中出现好多个A页。事实上,栈中只会有一个页A被重复弹出到栈顶。
vue计算属性get和set的作用和使用场景
<input v-model="sosoInput" type="text" :placeholder="tips">
。。。。。。。
computed: {
sosoInput: {
// getter
get: function () {
return this.$store.state.common.searchKeyword;------->getter从store获取数据
},
// setter
set: function (newValue) {
this.sosoInputValue = newValue;------->set将数据放入data的sosoInputValue中
}
}
},
。。。。。。。
例子中,没有将数据返回到store,因为需要最后‘确认’点击确定的按钮,才会通过store.commit()提交出去
遮罩处理
处理遮罩问题,当点击遮罩div的子,也会触发closePopup()函数,
办法1.在vue中加上'.self'修饰符
<div class="zhezhao" @click.self="closePopup">
办法2.事件目标对象===.zhezhao对象,即点击触发在div.zhezhao上,而非div.zhezhao的子类
if($event.target===this.$el.querySelector('.zhezhao')){