我的vue使用总结
1.监听vuex的state变化可以采用以下方式watch: {xxx: function(newVal,oldVal) {},},computed: {xxx() {return this.$store.getters.xxx;}},或者直接使用(因为vuex本身就是响应式的,一旦vuex中的state发生变化,会自动广播到所有使用的组件中)this...
1.computed做中间件 监听vuex的state变化
可以采用以下方式
watch: {
xxx: function(newVal,oldVal) {},
},
computed: {
xxx() {
return this.$store.getters.xxx;
}
},
或者直接使用(因为vuex本身就是响应式的,一旦vuex中的state发生变化,会自动广播到所有使用的组件中)
this.$store.getters.xxx (常用)
注意:同样的道理,computed也可以用来监听某个对象更深层的属性,如下
watch: {
xxx: function(newVal,oldVal) {},
},
computed: {
xxx() {
return this.obj.a.b;
}
},
2.vue的混入功能:mixins
主要用于不影响原文件的前提下,做一些新增的公用功能
把一个js文件当子组件插入到另一个组件里(如xxx.vue),用mixins进行引入,然后可以直接使用mixins.js里的东西。
冲突处理:其中created、mounted等是钩子函数;components、methods 、computed、data等为值对象;当遇到 值对象 冲突(对象键名相同)时,忽略mixins,只使用你组件中的 。当遇到 钩子函数 冲突时,mixins和你的组件都会被执行,且mixins中的会被优先执行。
mixins.js:(该文件中只有js部分,结构和.vue文件的js部分是一样的)
export const mixin = {
data () {},
methods: { fun(){}, ... }
}
xxx.vue:
import {mixins} from './mixins.js';
<template>
...
{{fun()}}
...
</template>
export default {
name: "xxx",
mixins: [mixins],
data() {...}
}
3.vue的过滤功能:filter
...
<el-table-column min-width='60' label="源文件">
<template slot-scope="scope">
<!-- 写法1,已经废弃 -->
<a class="operate" :href="scope.row.sourceUrl" download>{{scope.row.sourceUrl | getFileName}}</a>
<a class="operate" :href="scope.row.sourceUrl" download>{{scope.row.userName | makeUserName(prev)}}</a>
<!-- 写法2 -->
<p v-html="$options.filters.text()"></p>
</template>
</el-table-column>
...
data() {
return {
prev: 'super'
}
},
filters: {
getFileName(val){ //val就是sourceUrl
return val + '...'; //最后展示出来的结果
},
makeUserName(val, prev){ //在filters中无法直接获取this.prev,所以必须通过传参获取
return prev + val;
},
text(){
return 123;
}
}
4.vue中的键盘事件
在element-ui中
<el-input @keyup.native.enter="submit"></el-input> //回车按钮keyup时触发
在原生标签中
<input @keyup.enter="submit"></input>
5.slot-scope/scope的作用
在vue 2.5.0+ 中, slot-scope 替代了 scope
组件test:
<template> //template标签的作用就是包裹一段html代码,并在渲染页面后不体现自己
<div>
<div>下面是一个slot</div>
<slot a="123" b="444" ></slot>
</div>
</template>
使用组件test
//slot-scope表示获取组件test中slot的所有属性,组成对象slotProps(该对象名可随意取)
<test>
<template slot-scope="slotProps">
<div>下面是slot的props调用</div>
<div>{{slotProps.a}}</div>
<div>{{slotProps.b}}</div>
</template>
</test>
6.vue3.0代理配置,解决跨域问题
在根目录下创建vue.config.js文件,并写入以下代码:
module.exports = {
...
devServer: {
port: 8088, //端口号
host: '0.0.0.0', //匹配任意ip或域名
https: false, //配置本地 模拟为https,端口号需配为443
disableHostCheck: true, //默认检查hostname,如果hostname不是配置内的,将中断访问,设为true则不检查,但易受到DNS重新绑定攻击
open: true, //是否自动打开浏览器
proxy: { // 配置多个代理
'/api': {
//用于代理转发请求后台接口,当调用 localhost:8088/api/xxx 接口时,localhost:8088/ 会被替换成 target
target: 'https://mi-api-dev.nailtutu.com/',
ws: true, //是否启用websocket
changeOrigin: true, //是否改写源,即是否将localhost:8088/ 替换成 target,如需跨域则设为 true
pathRewrite: {
'^/api': '' //重写路径
}
},
'/pic': {
//当图片与接口不同源时,用于代理转发请求图片地址
target: 'https://cdn-dev.nailtutu.com',
ws: true,
changeOrigin: true
}
},
}
}
注意:在页面中使用接口时,需去掉域名,否则不会走代理
7.解决 build之后的dist目录 部署到服务器路由访问失败(一片空白)
原因:运行dev的话,可以用localhost:8080/xxx进行路由,但build之后的dist目录下,路由写法必须为localhost:8080/#/xxx
解决方法:
1.在vue.config.js中写入
module.exports = {
...
publicPath: './',
outputDir: 'dist',
lintOnSave: true,
runtimeCompiler: true, //关键点在这,调整内部的 webpack 配置
chainWebpack: () => {},
configureWebpack: () => {},
devServer:{...}
}
2.在router.js中
export default new Router({
// mode: 'history', //注释掉这2行 或 改为 hash 模式即可
// base: process.env.BASE_URL,
routes: [...]
})
3.重新build,或者重新运行 可生效
注意:移动端的H5页面一般用history模式的兼容性会比较好
8.vue移动端左右滑屏第三方插件
https://github.com/surmon-china/vue-awesome-swiper
9.vue实现i18n
1) 安装
npm install vue-i18n --save
2) 引入
import VueI18n from 'vue-i18n';
Vue.use(VueI18n); //注册插件
const i18n = new VueI18n({ //实例化
locale: 'en-US', //初始语言标识,通过this.$i18n.locale来实现语言切换
fallbackLocale: 'en-US', //当匹配不到以下语言列表时,强制指定用哪种语言
messages: {
'zh-CN': require('./common/lang/zh'), // 中文语言js静态文件
'en-US': require('./common/lang/en'), // 英文语言js静态文件
...
}
})
new Vue({
el: '#app',
i18n, //将实例化对象 注册到vue项目中
store,
router,
template: '<App/>',
components: { App }
})
3) 语言js文件
module.exports = {
userName: 'User Name:',
warning: 'This is not allowed',
...
}
4) 调用
//html中调用
<span>{{$t('userName')}}</span>
//js中调用
this.$t('warning')
10.Vue.nextTick的用法
作用:vue的数据更新是异步的,想确保拿到的是更新且渲染后的数据,就要用nextTick
写法:
<div ref="msgDiv">{{msg}}</div>
<div>{{msg1}}</div>
<div>{{msg2}}</div>
data(){
return {
msg: 'Hi',
msg1: '',
msg2: '',
}
}
methods: {
change() {
this.msg = "Hello";
this.msg1 = this.$refs.msgDiv.innerHTML; //msg1拿到的还是'Hi'
this.$nextTick(() => {
this.msg2 = this.$refs.msgDiv.innerHTML; //msg2拿到的才是'Hello'
})
}
}
11.vue样式模块化
vue的css除了用scoped关键字做局部化之外,还可以通过module关键字进行模块化
优点:比scoped有更多的控制权,可将该序列化的类名传给其他组件
用法:通过this.$style['button']可以获取具体类名
例1:
<template>
<button :class="$style.button" /> //最终渲染class名都会被序列化
</template>
<style module>
.button { color: red }
</style>
例2:
<template>
<div>{{ $style.primaryColor }}</div>
</template>
<style module lang="scss">
$primary-color: #B4DC47;
:export { //可用:export将scss变量导出,在this.$style中可获取到,也可传给其他组件
primaryColor: $primary-color
}
</style>
12.路由守卫
作用:避免没有权限,但知道路由的人访问页面
全局路由守卫:作用于所有路由,在main.js中写
router.beforeEach((to,from,next)=>{})
router.afterEach((to,from)=>{})
单路由守卫:作用于单个路由
{ name: "login" path: "/login", component: Login, beforeEnter:(to,from,next)=>{} }
组件内守卫:写在组件内
data(){},
beforeRouteEnter:(to,from,next)=>{ //在beforeCreate之前执行
next( vm => { //参数vm就是当前组件的实例,相当于this
....
})
},
beforeRouteLeave:(to,from,next)=>{ //在beforeDestroy之前执行
next();
},
beforeRouteUpdate:(to,from,next)=>{ //当本组件中存在二级路由导航时,且二级路由发生变化才会触发
next();
},
举例(全局路由守卫):
{ name: "login" path: "/login", component: Login, meta: {title: 'login'} }
{ name: "home" path: "/home", component: HomePage, meta: {requireAuth: true, title: 'home'} }
...
router.beforeEach((to,from,next)=>{
let token = window.sessionStorage.getItem('access_token');
window.document.title = to.meta.title;
if(to.meta.requireAuth){ //需要登录成功才可进入的路由
if(token){ //取得到登录信息,进行下一步
if(与权限配的菜单一致){
return next();
}else{
return next({name: 'noAuth'}); //跳转到无权限访问的模板页
}
}else{ //token失效
return next({path: '/login'});
或者
return next({name: 'login'});
}
}else{ //不需要登录权限,例如登录页
return next();
}
})
13.路由模式
详细解释:https://www.jianshu.com/p/1e854973ab26
hash模式(默认)
使用URL的hash来模拟一个完整的URL,当#后面的hash发生变化,不会导致浏览器向服务器发出请求,触发onhashchange这个事件,通过监听hash值的变化来实现更新页面部分内容的操作
注意:记得在vue.config.js中配置
module.exports = {
...
publicPath: './',
}
history模式
使用HTML5的pushState()和replaceState()这两个api来实现,同样,可以改变url地址且不会发送请求
区别
1) hash模式只能改变#后面的url片段,而history模式的pushState设置的新URL可以是与当前URL同源的任意URL
2) 在hash模式下,前端路由修改的是#中的信息,而浏览器请求时不会将 # 后面的数据发送到后台,所以刷新时不会有问题。但是在history下,你可以自由的修改path,当刷新时,如果服务器中没有相应的响应或者资源,则会刷新出来404页面。
14.路由跳转
name只能搭配params,path只能搭配query
//参数不会体现在地址栏中,所以再次刷新的话,页面会拿不到参数userId
<router-link :to="{ name: 'news', params: { userId: 123}}">text</router-link>
this.$router.push({ name: 'news', params: { userId: 123 }});
//参数会体现在地址栏中,所以再次刷新仍可拿到参数(推荐)
<router-link :to="{ path: '/news', query: { userId: 123}}">text</router-link>
this.$router.push({ path: '/news', query: { userId: 123 }});
push和replace的区别
this.$router.push //可返回上一页
this.$router.replace //替换了当前页,相当于只能返回上上页内容
back和go的区别 (底层也是history)
this.$router.back(0) //刷新
this.$router.back() //后退,原页表表单中的内容会保留
this.$router.go(-1) //后退+刷新,原页面表单中的内容会丢失
15.vue的深度监听
data(){
return {
person: {
firstname: 'Menghui',
lastname: 'Jin',
fullname: '',
other: {
name: 'a'
},
}
}
},
watch: {
person: {
handler(newValue,oldValue){
this.person.fullname = n.firstname + ' ' + this.person.lastname;
},
// immediate: true, //第一次加载立即执行handler,默认watch第一次不会执行
deep: true, //深度检测 person 对象的属性值的变化
}
}
注意1:deep为true只能正确检测到第一层,更深层次虽然可以进入handler,但newValue和oldValue都是一样的
注意2:用this.$set(this.other, 'name', 'b')也可以触发渲染
注意3:data中引用类型的数据,新增或删除是可以触发渲染的,只有修改(包括修改length)是不会触发的,所以才需要用this.$set
比如新增一个age属性,this.other['age'] = 10,这样是可以触发页面重新渲染的
16.vue父子组件中的方法互调
父组件调用子组件中的方法:
父组件:
<Child ref="myChild"></Child>
...
this.$refs.mychild.childMethod() //childMethod是子组件中的方法
子组件调用父组件中的方法:
子组件:
this.$parent.fatherMethod() //fatherMethod是父组件中的方法
17.vue路由配置404页面自动调整
1)在路由守卫中配置
router.beforeEach((to, from, next) => {
if (to.matched.length ===0) { //如果未匹配到路由
//如果上级未匹配到路由则跳转404页面,如果上级能匹配到则转上级路由
from.name ? next({ name:from.name }) : next({ name: 'page404' });
} else {
next(); //如果匹配到正确跳转
}
});
2)在router中配置
let router = new VueRouter({
routes:[
{path:'/',redirect:{name:"home"}}, // 重定向到主页
...
{path:'*',component: page404}, //*表示匹配全部;如果已有的路由全不匹配的情况下,返回404
或者{path:'*',redirect: '/page404'}, //用重定向也可以
]
});
18.不用vuex的情况下,兄弟组件之间传值的方式
let eventBus = new Vue; //事件车,用来连接两个兄弟
//组件A
methods:{
change(){
eventBus.$emit("changeGreen", 'green')
}
},
//组件B
created(){
eventBus.$on("changeGreen",(val)=>{this.color=val})
}
beforeDestroy(){
eventBus.$off("changeGreen")
}
注意:实际应用中可能会有问题。在页面不刷新的情景中(即不会进入beforeDestroy,比如用了keep-alive),当注册多几个事件之后,在来回切换的过程中会不断触发导致卡顿。解决方法:网上推荐用插件 vue-happy-bus 来处理即可。
19.vue动态组件
<component :is="xxx"></component>
<template>
<p v-for="(item, i) in arr" :key="i">
<component :is="item"></component>
</p>
</template>
<script>
data: {
arr: ['comA','comB'],
currentView: 'comA'
},
components: {
comA,
comB
}
</script>
20.如何让keep-alive标签中的组件重新渲染
1)用exclude属性
<keep-alive :exclude="[ 'name1', 'name2' ]"> // 对应 router 配置中的 name
<router-view :key="key"></router-view>
</keep-alive>
2)根据条件改变key值
3)在activated生命周期中刷新数据
activated() {
this.refreshData(); //只刷新数据,不刷新整体的dom
}
21.Vuex中更新对象或数组的值,视图不更新的解决办法
其实就是在mutation中使用全局的set方法去设置
import Vue from 'vue';
state: {
testObj: {},
},
mutations: {
setChatList(state, result){
// state.testObj.name = '张三'; // 错误 - 只会更新数据,不会更新视图
Vue.set(state.testObj,'name','张三') // 正确
}
}
22.异步组件加载及生命周期的控制
components: {
MyDemo: () => import('./Demo').then(component => {
component.default.mounted = ...
})
详情见:https://zhuanlan.zhihu.com/p/32015343
组件同步引入时生命周期顺序为:父组件的beforeCreate、created、beforeMount --> 所有子组件的beforeCreate、created、beforeMount --> 所有子组件的mounted --> 父组件的mounted
组件异步引入时生命周期顺序:父组件的beforeCreate、created、beforeMount、mounted --> 子组件的beforeCreate、created、beforeMount、mounted
23.按需引入echarts图表
npm install echarts --save
//加载echarts,引入主文件
import echarts from 'echarts/lib/echarts'
// 再引入你需要使用的图表类型,标题,提示信息等
import 'echarts/lib/chart/bar'
import 'echarts/lib/component/legend'
import 'echarts/lib/component/title'
import 'echarts/lib/component/tooltip'
24.引入公共样式
全局引入(在main.js中)
import '../static/css/global.css' /*引入公共样式*/
局部引入
<style>
@import './../static/css/global.css'; /*引入公共样式*/
</style>
25.v-for遍历的同时做v-if判断
这种写法一般会报警告,官方不推荐 v-for 与 v-if 在同一个标签中出现。
解决办法:套多一层标签,外面层用于 v-for,里面层用于 v-if
<div v-for="(item, index) in arr" :key="item.id">
<div v-if="item.xxx > 2">
...
</div>
</div>
26.手动销毁vue组件
this.$destroy('componentName'); //componentName就是组件的name
27.v-model如何与vuex结合使用
通过computed的get和set
注意:get和set不可用箭头函数的写法,否则获取不到this,因为隐式已经绑定了this
详情见:https://blog.csdn.net/weixin_33824363/article/details/91434500
28.vue中全局和局部引入批量组件的方法
用require.context实现
详情见:https://blog.csdn.net/Dalin0929/article/details/104557131
29.watch和computed的区别
更多推荐
所有评论(0)