前言
总结是基于vue2.x,vue-cli3.x,主要记录些,vue常用的指令、事件,监听、数据绑定、过滤器、组件、动画、vuex,vue-router等日常工作中时常用到的东西,也有些常用的插件和开发工具的介绍与使用,以及部分性能优化的建议与实践,如有不对,或不足的地方,也请各位大神,指出来,学习学习。
一、基础
1、理解mvvm
- m是vue实例中的data,自定义的数据或后端返回的数组,不是后端mvc里的model概念不同。
- vm是vue实例m和v之间的调度者 是mvvm的核心思想
- v是html要渲染的
2、常用指令
-
v-cloak 解决{{}}插值闪烁的问题
-
v-text 会先执行覆盖元素中原本的内容,但是插值表达式只会覆盖自己的占位符,默认不会闪烁
-
v-html 渲染html标签,覆盖元素中原有的元素内容
-
v-bind 简写为:用来绑定数据,可以写合法的js表达式
-
v-on 简写为@用来点击事件
3、常用事件修饰符
-
stop 阻止冒泡:外层和里层都有方法,点击会产生冒泡,也会触发外层事件。顺序从里到外产生事件
-
prevent 组织浏览器默认行为:a标签有浏览器默认行为
-
capture 捕获事件:点击里层先触发外层再触发里层,顺序从外到里产生事件
-
self 只触发自己本身的时间,不会产生冒泡和捕获事件,类似于阻止冒泡,但只针对自己那一层,最外还是会被里层冒泡冒到,stop是阻止所有层次
-
once 事件只执行一次
4、数据的绑定
-
v-bind:数据的单向绑定
-
v-model:数据的双向绑定,只能用于表单元素中
tips:表单元素:radio、text、address、email、select、checkbox、textarea
5、class绑定
-
1.数组带对象
data(){ return{ flag:true } }
tips:可以在勒种更多数组中写三元表达式,但是推荐使用对象来代替它控制是否渲染
-
2.单纯的对象
data(){ return{ falg1:true, falg2:true } }
-
3.数组带带三元
data(){ return{ falg:true, } }
-
4.对象升级
data(){ return{ classObj:{classA:falg1,classB:flag2} } }
tips:直接使用一个对象数组来控制样式
-
5.使用style的对象来实现样式的修改
<div :class="styleObj" /> data(){ return{ styleObj:{color:red} } } -
6.使用style的数组带对象来实现样式修改
data(){ return{ styleObj1:{color:red}, styleObj2:{color:red} } }
6、v-for的使用
可以遍历:普通数组、对象数组、对象、还可以是数字
<div v-for='(item,key,index) in object' :key='index'>
{{item}}--{{key}}--{{index}}
</div>
<div v-for='(count in 10)'> </div>
**tips:**在遍历对象的时候有多个index索引,遍历数字时是从1开始的。绑定key时属性值必须是number或者string
7、v-if、v-show
-
v-if有较高的切换性能,适合元素可能永远不会被用户看到
-
v-show有较高的初始渲染消耗,适合元素的频繁切换
8、调试插件
- 在谷歌商店找vue-devtools插件,使用这个插件,并设置插件,允许访问文件地址。会在调试中出现vue相关的东西
- debugger直接可以调试
9、过滤器
全局和私有过滤器
<div v-for='(item,key) in object' :key='index'>
{{item | dateFormat}}
</div>
<div v-for='(count in 10)'> </div>
-
全局
vue.filter('过滤器名称',function(){
})
-
私有(局部)
filters:{ dateFormat:function(data,param){ do some } }
tips:
-
data就是 | 第一个参数,已经被定死了,永远是管道左边要被转换的数据,param是过滤方法传进来的其他参数,过滤器采用就近优先原则,如果私有和全局的名称一样就优先采用私有的。
-
padstart和padend es6的补0方法
-
第二个参数时字符串,第三个参数时表达式,如果自定义参数值是动态的会报错。目前就是的简单的过滤用过滤器,复杂点的用方法,能用计算属性的用计算属性 有缓存,能提高性能。
10、按键修饰符
-
监听pc键盘上的值
<input @keyup.enter='方法名'>
**tips:**enter可以换成键盘上的任何一个值,只要去找相关的键盘码,就都可以使用,推荐设置个别名。放在没有按钮操作的模板。
- 自定义全局按键修饰符
Vue.config,keyCodes.f2 = 113,就可以用了
**tips:**f2修饰符是vue里没有定义的自己创建
11、定义指令
1.全局
定义的指令都要按规定去创建,在bind和inserted还有updated中去创建
Vue.directive('focus'{
//每当指令绑定到元素上的时候,会立即执行bind 函数,只执行一次,
注意:在元素刚绑定元素的时候,还没有插入到dom中去,这时候,调用focus方法没有作用,即放在focus 放在bind中是不起作用 的
bind:function(el,binding){
el.style.color=binding.value
},
//表示元素插入到dom中的时候,只执行一次
inserted:function(){
el.focus() js行为放在这里去创建
},
//当组件更新的时候,可能会触发多次
updated:function(){},
})
tips:
-
参数1:指令名称,在定义的时候,指令名称前面不需要加v-前缀,但是调用的时候,必须在指令名称前加v-前缀
-
参数2:是一个对象,在这个对象上,有一些指令相关的函数,这些函数可以在特定的阶段执行相关的操作
-
在每个函数中的第一个参数永远是el,el代表被bind的元素,el是原生的js对象
2.局部
directives:{
'指令名':{
bind:function( el,b){
}
}
}
3.简写
'指令名':function(el,binding){
} //注意这个function 等同于 把代码写到bind和update中去
**tips:**样式相关的指令放在bind中,js相关的放在inserted中比较合适,防止指令不生效,使用场景写组件时可以用这个区改样式
12、生命周期
-
beforeCreate():这是我们遇到的第一个生命周期函数,表示实例完全被创建出来之前,会执行该函数
-
created():这是我们遇到的第二个声明周期函数
-
beforeMount():模板已经在内存中编辑完成,但是尚未把模板渲染(挂载)到页面中。在beforeMount执行的时候,页面中的元素还没有真正的被替换过来,只是之前写的一些模板字符串。就像{{text}}这样
-
mounted():表示内存中的模板已经真实的挂载到了页面中,用户此时已经可以看到渲染好的页面了。只要执行完这个在生命周期,就表示整个vue实例已经初始化完毕了。此时,组件已经脱离了创建阶段,进入到了运行阶段
-
beforeUpdated():这时候表示我们的页面还没有完全被更新,但是数据已经被更新了,页面中显示的数据还是旧的。此时data数据时最新的,页面尚未和最新的数据保持同步
-
updated():执行的时候先根据data中最新的数据,在内存中重新渲染处的一份最新的内存dom树,当最新的内存dom树被更新后,会把最新的内存dom树重新渲染到真实的页面中去。这时候就完成了数据data(model层)->view(视图层)的更新,页面和data数据已经保持同步,都是最新的了
-
beforeDestroy:当执行beforeDestroy钩子函数的时候,vue实例就已经从运行阶段进入了销毁阶段,实例身上所有的data和所有的methods以及过滤器、指令等都处于可用状态,此时还没有真正的执行销毁过程
-
destroyed:当执行这个函数的时候,实例身上所有的data、指令、方法等都不可以再用了
13、过渡类名实现动画
1.vue的内置动画
<style>
.v-enter,
.v-leave-to{
opacity:0;
transform:translateX(150px) --这东西是位移
}
.v-enter-active,
.v-leave-active{
transition:all 0.4s ease;
}
</style>
<transition name='my'>
<h3 v-if="flag"></h3>
</transition>
<script>
data(){
return {
flag:false
}
}
</script>
2.使用第三方类实现动画
<transition enter-active-class="bounceIn"
leave-avtive-class="bounceOut" duration='200'
>
<h3 v-if="flag" class="animated" ></h3>
</transition>
3.在属性中声明js钩子 实现半场动画(只需要进场,不需要离场)
<transition
<div
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
>
</div>
</transition>
<transition
<div
v-show="flag"
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
>
</div>
</transition>
<script>
methods:{
beforeEnter(el){
//动画入场之前,此时动画尚未开始, 可以在beforeEnter中设置元素开始动画之前的初始位置
el.style.transform=
"translate(0,0)"
},
enter(el,done){
/*这句话,没有实际的作用,但是,如果不写,出不来动画效果,可以认为 这个会强制刷新动画,ofset触发了重绘重排导致动画更新了*/
el.offsetWidth
el.style.transform=
"translate(150px,450px)"
el.style.transition='all 1s ease'
/*这里的done 代表着
afterEnter的引用,
这个会立即执行afterEnter 否则会有延时
*/
done()
},
afterEnter(el){
/*动画完成之后,会调用afterEnter */
this.flag=!this.flag
}
}
</script>
4.在实现列表过渡的时候,如果需要过渡的元素是通过v-for循环渲染出来的,不能使用transition包裹,需要使用transitionGroup
<transition-group appear tag='ul'>
<li v-for >
<li>
</transition-group>
.v-enter,
.v-leave-to{
opacity: 0;
transform:translateY(80x);
}
.v-enter-active,
.v-leave-active {
transition: all 0.6s ease;
}
/*离开后下一个东西没有动画使用这个可以使用动画实现下一个东西渐渐地飘上来的效果,要和 v-leave-active的absolute 配合 固定写法*/
.v-move {
transition:all 0.6s ease
}
.v-leave-active{
/* absolute 有个特点元素默认宽度就是最小值,要在元素上添加width:100%*/
position:absolute;
}
<transition mode="out-in">
<component :is="comName" >
</component>
</transition>
tips:
- v-enter【这是一个时间点】是进入之前,元素的起始状态,此时还没有开始进入
- v-leave-to【这是一个时间点】是动画离开之后,离开的终止状态,此时元素动画已经结束了
- v-enter-active【入场动画的时间段】
- v-leave-active【离场动画的时间段】
- animated是个动画库,新版本似乎不需要加入
- 使用:duration=200来表示动画的时间,如果只写一个表示统一配置了开场和离场时间,用对象可传入c入场和离场 duration=“{enter:200,leave:400}”
- 添加appear属性,实现页面刚展示出来,入场时的效果
- 通过transition-group元素,设置tag属性指定transition-group渲染为指定元素,如果不指定tag属性,默认渲染为span标签
- mode="out-in"先过渡再进来,防止有阴影,用mode来设置过渡方式
**注意:**最外层一定要用transition包裹着,动画似乎升级了,可以在transition标签中加入name属性,并且在css样式中把v,替换成你的name属性值
14、组件
1.使用Vue.extend来创建全局的Vue组件
var coml=Vue.extend({
template:'<h3>这是使用Vue.extend 创建的组件</h3>'
})
//第一个参数组件名称,第二个参数创建出来的组件模板对象
Vue.component('myComl',coml)
<my-coml><my-coml/>
2.使用vue.component来创建组件
Vue.component('mycom2',{
template:'<div>
<h3>
这是直接使用Vue.component 创建出来的组件
</h3>
</div>'
})
3.使用template来创建组件
<template id='tmp1'>
<div>
<h1>
这里通过template元素,在外部定义的组件结构,这个方式,有代码的智能提示和高量
</h1>
</div>
</template>
Vue.component('mycom3',{
template:'#tem1'
})
4.私有组件component
<template id='temp2'>
<h1>这是私有login组件</h1>
</template>
componment:{
login:
{
template:'tmpl2'
}
}
-
如果使用了Vue.component定义了全局组件,组件名称使用驼峰命名,在引用时大写的驼峰要改为小写,两个单词之间用 - 进行连接
-
Vue.component第一个参数:组件的名称,将来在引用组件的时候,就是使用标签的形式进行引用的。第二个参数:Vue.extend创建的组件,其中template就是要展示的内容
-
注意:不论是哪种方式创建出来的组件,组件的template属性指向的内容模板,必须有且只能有唯一一个根元素
15、组件里的data
- 组件可以有自己的data数据
- 组件data和实例中的data有点不一样,实例中data可以为一个对象,但是组件中的data必须是一个方法
- 组件中的data除了必须是一个方法之外,这个方法内部还必须返回一个对象
- 组件中的data数据和实例中的data使用方式完全一样
- 组件中的data为什么必须是个方法且要返回一个对象呢?因为要确保没有实例中的数据时唯一的,如果data中的数据时放在实例外部将会被其他实例共享。
16、组件切换
1.组件里的切换可以用v-if和v-else进行切换即标签页切换
<a href=""
@click.prevent="flag=true"
>
登录
</a>
<a href=""
@click.prevent="flag=flase"
>
注册
</a>
<login v-if="flag">
</login>
<register v-else="flag">
</register>
2.vue提供了component,来展示对应名称的组件
//component 是一个占位符
:is属性,可以用来指定要展示的组件的名称 写死的时候这个组件名要是个字符串,动态绑定时key普通写法就好,但value必须是字符串。
<component :is="'componentId'">
</component>
<component :is="oneName">
</component>
data(){
return{
oneName:"login",
}
}
17、父子组件通讯
-
父子组件传值,通过v-bind:(:)来传值,使用props来接收值
-
父组件用事件绑定机制传递方法给子组件v-on简写@
//父组件中 <component-name :children='children' //传值 @handle='show' //绑定方法
data(){
return(){ children:11 }}
methods:{
show(data){ }}
3.emit英文原意:触发、调用的意思
@handle=show父组件传show方法给子组件
子组件接收父组件的方法,并用$emit把子组件的值传给父组件
//子组件中
methods:{
handle(){
this.$emit('func',{
age:1,
name:'搞事'
})
}
}
4.在父组件中接收子组件所有参数的同时,添加自定义参数
1.子组件传出单个参数时:
// 子组件
this.$emit('test',this.param)
// 父组件
@test='test($event,userDefined)'
2.子组件传出多个参数时:
// 子组件
this.$emit('test',this.param1,this.param2, this.param3)
// 父组件 arguments 是以数组的形式传入
@test='test(arguments,userDefined)'
**tips:**子组件中的data数据,并不是通过父组件传递过来的,而是子组件自身私有的,比如子组件通过ajax请求回来的数据,都可以放在data上,data上的数据都是可读可写的
18、使用ref获取dom元素
<h3 id='myh3' ref='myh3'> </h3>
methods:{
getElement(){
console.log( this.$refs.myh3.innerText)
}
}
//组件也可以使用ref,让父组件调用子组件里的方法和属性值
<login ref='mylogin'> </login>
methods:{
getElement(){
//父组件调用子组件里的属性值
console.log(this.$refs.mylogin.msg)
}
}
tips:
- refs;s代表多个引用,会有多个dom元素
- ref英文是reference。值类型和引用类型
19、路由
**1.router-view这是vue-router提供的元素,用作占位符。**当路由规则匹配到组件,将会展示到该元素中
<router-view></router-view>
2.路由切换,模板写法默认会渲染成一个a标签
使用tag的span可以用来转换模板的标签名
<router-link to="/login" tag='span' >
登录
</router-link>
3.路由配置
new VueRouter({
//路由匹配规则
routes:[
{
path:'/',
redirect:'/login'
},
{
path:'login',
component:login
},
{
path:'/register',
component:register
}
]
//路由高亮的类名
linkActiveClass:'myactive'
})
var vm=new Vue({
el:'#app',
data:{},
methods:{},
router //将路由规则对象注册到vm实例上,用来监听Url地址的变化,然后展示对应的组件。
})
4.路由传参
1)query
//获取id
this.$route.query.id
2)在path上传参
//参数要一一对应不可缺失,不然可能会
造成路由的不匹配
< router-link
to="/login/12/ls"
>
{
path:'/login/:id/:name',component:login
}
3.params新的方式可以看文档
4.子路由
<router-link
to="/account/login"
>
</router-link>
routes:[
{
path:'/account',
component:account,
children:{
{
path:'login',
component:login
}
}
}
]
tips:
- 每个路由规则都是一个对象,有两个必须的属性
- 属性1是path,表示监听路由监听地址
- 属性2是component,如果路由匹配到属性1的path,则展示component属性对应的组件
- 子路由不能添加/,加了/会以根目录为匹配基准
- 超链接的to一定要加上父路由
注意:component属性值,必须是一个组件的模板对象,不能是组件的引用名称
20、命名视图实现经典布局
根据name来找组件
<router-view></router-view>
<router-view name="left"></router-view>
<router-view name="main"></router-view>
var header={
template:'<h1>header</h1>'
}
var leftBox={
template:'<h1>leftBox</h1>'
}
var mainBox={
template:'<h1>mainBox</h1>'
}
{
path:'/',components:{
'default':header,
'left':leftBox,
'main':mainBox
}
}
21、watch
监听非dom元素
watch:{
'obj.a'(newValue,oldValue){ },
immediate:false
}
watch:{
'obj':{
handler (newValue, oldValue) {
}
},
deep:true //深程度监听 性能消耗大
}
watch:{
//监听路由
'$route.path':{
handler (newValue, oldValue) {
}
},
//immediate:true代表如果在 wacth 里声明了之后,就会立即先去执行里面的handler方法,如果为 false就跟我们以前的效果一样,不会在绑定的时候就执行
immediate:true
}
tips:
- 用了obj.a加上handle+immediate:true,就可以监听对象里的值,如果是obj加上handle+deep:true也是可以监听对象的属性,但是性能消耗大,一般是直接对象>>+属性
- 用handle方法可以让watch初始化就执行,如果不用handle它就先不执行,待数据改编再执行
- 不要在watch和computer中去修改参与计算或者监听的值,而是要生成新的值
22、computed
computed:{
'fullname':(){
return
}
}
23、render函数注册组件(vm[vue实例]的属性)
render:function(createElements){
//createElements是一个方法,调用它,能够把指定的 组件模板 渲染为html结构
return createElements(login)
//注意 这里 return 的结果,会替换页面中el 指定的那个容器
}
**tips:**render和components区别render会把整个app里组件全部覆盖,一个app中只能放一个render组件,components可以放置多个且不会覆盖
24、slot插槽
1.写插槽
<div v-if="layout === 'block'" class="layout-block" :class="scroll?'layout-scroll':''">
<slot></slot> //匿名插槽
</div>
<!-- 左右块 -->
<div v-if="layout === 'both'" class="d-flex jc-between">
<div class="layout-both" :class="scrollLeft?'layout-scroll':''">
<slot name="left"></slot> //有名字的插槽
</div>
<div class="layout-both" :class="scrollRight?'layout-scroll':''">
<slot name="right"></slot>
</div>
</div>
2.使用插槽
//有名字的插槽 # v-slot的缩写是#
<template #left></template>
<template v-slot="left" > </template>
二、杂项
1、nrm
安装nrm
- nrm i nrm -g 全局安装
- nrm ls 显示列表
- nrm use npm 使用nrm use后有很多地址可选择
tips:nrm只是单纯的提供几个常用的下载包url地址,且能让我们在这几个地址之间很方便的进行切换,但实际上:我们每次使用的安装工具都是npm 和nrm不一样
npm i cnpm -g
2、webpack
在网页中会引用哪些常见的静态资源:
- js(.js .jsx .coffee .ts(typescript))
- css (.css .less .sass .scss)
- Image (.jpg .png .gif .bmp .gif)
- Fonts (.svg .ttf .eof .woff .woff2)
- 模板文件(.ejs .jade .vue)
3、热部署
webpack-dev-server实现自动打包功能,浏览器不用刷新也能看到文件已经修改,打包的文件并没有放在实际的物理磁盘上,而是直接托管到电脑内存中。而在我们的项目根目录中根本找打不到这个打包好的文件,该文件和src,dist,node_modules平级的一个看到的文件
4、热更新
hot网页不重载,直接更新,加快打包速度不生成新文件
"scripts":{
"dev":"webpack-dev-ser ver --open --prot 3000 --contentBase src --hot "
}
在配置文件中进行热更新配置
devServer:{
hot:true
}
5、webpack引入vue
在webpack中,使用以下方式导入Vue
构造函数,功能并不完善,只提供了runtime-only方式,并未提供在网页中使用的方式
阉割版:
import Vue from 'vue'
齐全版
1.
import Vue from '../node_modules/vue/dist/vue.js'
2.
module.exports={
resolve:{
//设置 Vue被导入的时候的包的路径
alias:{
"vue$":"vue/dist/vue.js"
}
}
}
tips:包的查找规则
-
看项目根目录中是否存在node_modules的文件
-
在node_modules中 根据包名,找到对应的vue文件
-
在vue文件夹中,找到package.json包配置文件
-
在package.json中查找main属性(main属性指定这个包在被加载的入口文件)
-
改了webpack的包需要重新运行项目
6、在webpack中通过render展示组件
如果想要通过vue,把一个组件放到页面中展示,vm实例中的render函数可以实现
render:function(createElement){
return createElement(login)
}
//就一行可以省略{} 并且没有花括号默认就有return,
简写: render: c => c(login)
tips:webpack中如何使用vue
- 安装vue包
- 由于在webpack中,推荐使用.vue定义组件,需要安装解析的loader
- 在main.js中导入vue模块 import Vue from ‘vue’
- 定义一个.vue组件,其中组件有三部分组成
- 使用import login from './login.vue'导入login组件
- 创建vm的实例 var vm = new Vue({el:'app',render:c=>c(login)})
- 在页面创建一个id为app的div元素,作为vm实例的控制区域
7、export default 和export
-
export default向外暴露的成员,可以使用任意变量进行接收
-
在一个模块中,export default只允许向外暴露1次
-
在一个模块中,可以同时使用export default 和 export向外暴露成员
-
使用export向外暴露的成员,只能使用{}的形式来接收,这种方式叫(按需导出)
-
export可以向外暴露多个成员,如果我们在import的时候并不需要某些成员,则可以不在{}中定义
-
注意使用export导出的成员,必须严格按照导出时候的名称用{}进行按需接收
-
使用export导出的成员,如果想换个名称进行接收,可以使用as来取别名
const arr={ a:'1', b:'2' } export default arr
/* export default { 这个暴露是错误的所以当前注释 一个js文件中只能暴露一次 address:'北京' } */
export title=1 import arr, {title as title1 } from '/xxx.js'
8、router
-
render会把el指定的容器中的所有内容都清空覆盖,所以不要把路由的router-view和router-link直接写到el所控制的元素中
-
注意app这个组件,是通过vm实例的render函数渲染出来的。render函数如果要渲染组,渲染的结果只能放在el:"#app",el指定的#app中(好啰嗦)
-
Account和goodList组件是通过路由匹配监听到的,这两个组件只能展示到所属路由的
-
子路由的应用场景在标签页切换
9、scoped原理
样式的scoped是通过css的属性选择器来实现的 .aa[vsfp]{color:red}
tips:vsfp是哈希值
10、promise
-
模拟promise
getFution(aa,callback){ callback(aa)
}getFution(aa,funtion(res){ console.log (aa) })
-
异步操作
每当new一个promise实例的时候,就会立即执行这个异步操作中的代码。
也就是说,new的时候除了能够得到一个promise实例之外,还会立即调用promise构造函数传递的function,执行该function中的异步操作代码。
var promise=new Promise(function(resolve,reject){
异步操作,ajax函数等,而且可以自由输出东西了
resolve(true)
reject(false)
})
getFunction(){
var promise=new Promise(function(){
异步操作,ajax函数等,而且可以自由输出东西了
})
}
getFunction(aa) .then(function(data){
console.log(data)
return getFunction() --返回后,可以使用后续的then
}.then(function(data){
console.log(data)\
return getFunction()}).then(funtion(data){
console.log(date)
})
//捕获只放在最后面。前面有任何的异常都会终止
.catch(function(data){
console.log(data)
}
tips:在‘then’里面写多个返回错误的方法的不可取的
11、vuex
vuex是为了保存组件之间共享数据而诞生的,如果组件之间又要共享的数据,可以直接挂在到vuex中,而不必通过父子组件之间传值了,如果组件的数据不需要共享,此时这些不需要共享的私有数据,就没必要放到vuex中
vuex存放共享数据
data存放私有数据
props存放父组件传过来的数据
操作vuex里的state
直接操作store里的属性值,不推荐这种做法
this.$store.state.属性值
-
推荐只通过mutations提供的方法,才能操作对应的数据
mutations:{ increment(state,payload){ state.count++ } } this.$store.commit('方法名')
-
vuex里的getters
如果
store中state上的数据,在对外提供的时候,需要做一层包装,那么推荐使用getters。optCount:state=>state.count this.$store.getters.***
tips:increment方法里的state是属于vuex里的state;count是state里的属性;payload外部传进来的值,用来修改state里属性的值。最多只能支持两个参数,可以是数组和对象
12、ngrok
可以映射本地80端口,把本地地址映射为外网地址
npm地址:
//npm下载 --感觉下的有点慢 换个路径下比较好
npm install ngrok -g
//命令
ngrok http 80
tips:需要开启本地服务器, 映射后只是映射www路径,不是完成的程序路径,需要自己补充完整。
13、public目录下的图片如何require引入
//第一种 图片质量小的可以自动转换为base64的
img: require("@/../public/img/home/user.jpg ")
//第二种 这里可以把最前面的 / 看做是public
/img/abnormal/Trash.png
即 public/img/abnormal/Trash.png
tips:@是指src目录..@的上一级目录,在进入public
三、性能的优化建议
1、watch如果是obj加上handle+deep:true 也是可以监听对象的属性,但是消耗性能很大
2、computed里生成的值,会有缓存,不建议用函数去处理一些值的计算,使用computed性能更高
3、:key="id"
- id是列表返回的id,如果没有id就写item,不建议写index(eslint会有警告信息),写上key会有缓存减少消耗
4、v-once和v-model的区别是:v-once只会绑定一次,不会重新更新内容。可以减少开销
- 应用场景:只读场景,不进行修改页面的时候
5、v-for和v-if不适合在同一个div中使用
-
可以在最外层套用一个template来解决
6、this.$parent可修改父组件值,但不建议
7、gzip优化
-
vue配置,在前端生成带有gz的文件
-
辅助插件:compression-webpack-plugin
const CompressionWebpackPlugin = require('compression-webpack-plugin') const productionGzipExtensions = ['js', 'css'] const isProduction = process.env.NODE_ENV === 'production'
configureWebpack: config => { if (isProduction) { config.plugins.push( new CompressionWebpackPlugin({ algorithm: 'gzip', test: new RegExp('\.(' + productionGzipExtensions.join('|') + ')$'), threshold: 10240, minRatio: 0.8 }) ) } },
nginx服务端配置
//配合前端的gzip
在站点配置添加如下代码:
location ~* \.(css|js)$ {
gzip_static on;
}
这是 nginx 的静态 gzip功能,会自动查找对应扩展名的文件,如果存在 gzip 文件,就使用,如果没有就用原文件
//后端返回gzip
gzip on;
gzip_static on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
8、cdn加速
<script src="https://unpkg.com/vue@2.6.10/dist/vue.runtime.min.js"></script>
<script src="https://unpkg.com/vuex@3.0.1/dist/vuex.min.js"></script>
<script src="https://unpkg.com/vue-router@3.0.3/dist/vue-router.min.js"></script>
<script src="https://unpkg.com/axios@0.19.0/dist/axios.min.js"></script>
<script src="https://unpkg.com/element-ui@2.9.2/lib/index.js"></script>
/有了config就按以下配置
configureWebpack: config => {
//cdn
config.externals = {
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter',
axios: 'axios'
}
if (isProduction) {
config.plugins.push(
new CompressionWebpackPlugin({
algorithm: 'gzip',
test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
threshold: 10240,
minRatio: 0.8
})
)
}
}
9、网页中引入的静态资源多了后会有什么问题?
- 网页加载速度慢,因为要发起很多的二次请求
- 要处理错综复杂的依赖关系
- 解决方案:
- 合并、压缩、精灵图、图片的base64编码、cdn
- 可以使用之前学过的requireJs、也可以使用webpage
10、建立不同的环境变量(开发、测试、正式)
一、建立环境配置文件
在package.json 同级的目录下 建立3个文件
1 .env.development --开发环境 (本地环境)
2 .env.production --正式环境 (正式线服务器--打包)
3 .env.test --测试环境 (测试线服务器--打包)
二、在每个文件中写入具体的配置内容
/*****.env.development文件的内容*****/
NODE_ENV = 'development'
VUE_APP_CURRENT_MODE = 'development'
/*****.env.production文件的内容*****/
NODE_ENV = 'production'
VUE_APP_CURRENT_MODE = 'production'
/*****.env.test*****/
NODE_ENV = 'production'
VUE_APP_CURRENT_MODE = 'test'
三、在package.json 中写入
1.在纯粹的vue_cli3.x配置如下
"scripts": {
"serve": "vue-cli-service serve --mode development",
"build": "vue-cli-service build --mode production",
"build:test": "vue-cli-service build --mode test",
},
2.在uni-app下的vue_cli3.x的配置
"scripts": {
"serve": "npm run dev:h5 -- development", //修改点
"build": "npm run build:h5 -- production", //修改点
"build:test": "npm run build:h5 -- test", //修改点
"build:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build --mode", //修改点
"build:mp-alipay": "cross-env NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build",
"build:mp-baidu": "cross-env NODE_ENV=production UNI_PLATFORM=mp-baidu vue-cli-service uni-build",
"build:mp-toutiao": "cross-env NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build",
"build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build",
"dev:h5": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve --mode", //修改点
"dev:mp-alipay": "cross-env NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch",
"dev:mp-baidu": "cross-env NODE_ENV=development UNI_PLATFORM=mp-baidu vue-cli-service uni-build --watch",
"dev:mp-toutiao": "cross-env NODE_ENV=development UNI_PLATFORM=mp-toutiao vue-cli-service uni-build --watch",
"dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch",
"info": "node node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js"
},
tips:以上不同环境的切换点,修改点主要就是mode --‘环境变量’
四、各种插件的介绍和引用
1、postcss-plugin-px2rem
配置文件名postcss.config.js vue-cli3.x脚手架自带px转rem等单位的配置。
module.exports = {
plugins: [
require('autoprefixer')(),
require('postcss-plugin-px2rem')({
rootValue: 192, //设计图的宽度/10
unitPrecision: 10, //换算的rem保留几位小数点
mediaQuery: true,
minPixelValue: 3
// exclude:/node_modules|folder_name/i,把第三方的框架排除掉
})
]
}
2、babel-plugin-transform-remove-console
删除console,在根目录中新建.babelrc文件,并配置:
//第一种
{
"env": {
"production": {
"plugins": [
["transform-remove-console", { "exclude": ["error", "warn"] }]
]
}
}
}
3、html-webpack-plugin
当使用html-webpack-plugin之后,我们不需要手动后处理bundle.js的引用路径。因为该插件已经自动创建了一个合适的script并正确引用
/*导入在内存中生成html页面的插件,只要是插件,都一定要放到plugins节点中去
*/
const htmlWebpackPlugin=require("html-webpack-plugin")
//创建一个 内存中 生成html 页面的插件
new htmlWebpackPlugin({
template:path.join(__dirname,'./src/index.html')
filename:'index.html'
})
//这个节点,用于配置 所有 第三方模块 加载器
module:{
rules:[
{test:/\.css$,use:[]}
]
}
4、prerender-spa-plugin
构建阶段生成匹配预渲染路径的 html 文件