Vue实例和容器一一对应

提示❗❗❗❗❗


数据绑定

  • v-bind:/:单向绑定
  • v-model:value/v-model:双向绑定;默认绑定value值

他有3个修饰符
lazy 懒加载,失焦再…–
number 控制传入data的值是数字型–
trim 清除两边空格–

checkbox如果没有配置value值,那收集的就是checked值–
checkbox如果配置value值,初始值为数组就收集value组成的数组,不是数组收集checked

v-model不要绑定传递过来的prop,不推荐


$mount(‘#id’)

  • vue实例.$mount('#id')指定为vue实例指定容器
  • 还可以el$el都不要,写配置template:{ '<div>...</div>' }

如果要换行需要用模板语法


由Vue所管理的函数不要用箭头函数,不然this会指向window


数据代理

  • 数据代理原理 为对象添加属性
Object.defineProperty(person,'age',{
value:,
enumerable:, 属性是否可枚举,默认false
writable:, 属性是否可修改,默认false
configurabl:, 属性是否可删除,默认false
get(){return} 读取age属性时,函数被调用,返回值为age的值
set(newalue){return} 修改age属性时,函数被调用,会收到修改的具体值
})

事件绑定

  • v-on:/@ 定义事件默认传递参数event鼠标事件
    • event.target是触发此事件的元素;
    • 如果要传递参数并保留event,则@click=function(参数1,$event)
  • 事件:
    • click 点击;
    • scroll 滚动条滚动;
    • wheel 滚轮滚动;
    • keydown 键盘按下;
    • keyup 键盘起来

修饰符:(修饰符可连写)

  • prevent 阻止默认事件
  • stop 阻止时间冒泡
  • once 事件只触发一次
  • capture 执行捕获模式
  • self 只有event.target是当前操作元素才出发
  • passive 事件默认行为立即执行,无需等待回调函数
  • native 执行vue定义的原生事件

按键别名:

  • enter 回车
  • delete 删除
  • esc 退出
  • space 空格
  • tab 制表符
  • up
  • down
  • left
  • right
  • caps-lock 大小写转换(两个单词转换为短横线命名)

data中的数据会做数据代理所以不需要数据代理的放在其他配置项里面,如methods...


计算属性computed

  • 原理:数据代理
  • 完整写法:
number:{
  get(){},
  set(val){}
}
  • 简写:
number(){
  return
}

如果计算属性只读,那就用简写方式


监视配置

监视完整写法:

xxx:{
  deep:true//深度监视
  immediate:true//先执行一次
  ...
  handler(){}
}

handler其实就是监视的简写,接收两个参数新值与旧值


计算属性和监视:

  • 监视可以完成异步操作
  • 配置里的函数不能写箭头函数,不然this指向是window,配置里的属性里的函数用箭头函数,this指向vm

绑定class样式:

  • :class="1 2 3"字符串绑定 适用确定且少
  • :class="[1,2,3]"数组绑定 适用数量类名不确定
  • :class="{1:true,2:false,3:true}"数量类名确定

绑定style样式:

  • :style="{fontSize:'10px'}"对象绑定
  • :style="[{},{}]"数组绑定

条件渲染

  • v-show隐藏节点,节点还在
  • v-if隐藏节点,节点不在;v-ifv-else-ifv-else同理js代码中的条件判断,需要挨在一起
  • template标签不能和v-show连用

遍历:

  • v-for="(item,index) in/of arr" :key=index
  • v-for="(value,key) in/of obj" :key=key
  • v-for="(number,index) in/of number" :key=index
  • v-for="(str,index) in/of str" :key=index

key原理:

  • 没有啥逆序操作的时候用index作为key是没问题的,其他最好用唯一标识

Vue检测数据改变原理(待完善)

  • 构造函数中的this就是用构造函数创建的实例对象
  • 部分代码原理
let data = {
    name: 'xx',
    age: 10
  }
let obs = new Observe(data)
let vm = {}
vm._data = data = obs
function Observe(obj) {
    let keys = Object.keys(obj)
    keys.forEach(k => {
        Object.defineProperty(this, k, {
                get() {
                    return obj[k]
                },
                set(newVal) {
                    console.log('便楼')
                    obj[k] = val
                }
            }
        )
    })
}

Vue.set()方法

为实例数组/对象添加属性

对象

  • Vue.set(target,key,val)
  • vm.$set(target,key,val)

数组

  • Vue.set(target,index,item)
  • vm.$set(target,index,item)

target不能是vmvm.data/vm._data即不能是根
他只能给data中的对象添加属性


数组的检测原理

  • Vue不会为数组元素添加响应式的gettersetter,所以通过下标更改数组数据是无法被Vue所监测到的。针对数组,只有通过调用pushpopshiftunshiftsplicereversesort这7个改变原数组本身的API,才会引起Vue的响应
  • 直接赋值修改不行,但是xx[index].key=xxx这样就行;xx[index]=xxx这样不行

过滤器fliter

  • 管道运算符 | 一次把前面的值传递给后一个作为参数—
  • dayjs(时间戳).format()转换时间戳为时间,格式自查在bootcdn官网

dayjs在线库链接<https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.3/dayjs.min.js>


指令

  • v-text 内容以文本方式呈现
  • v-html 解析html语句(此方法不能用于用户输入区,容易引发xss攻击)
  • v-cloakVue接管容器的时候这个属性会被Vue移除,可以用来在网速慢的时候先不展示容器
  • v-pre, Vue跳过此节点

自定义指令:配置directives

<p v-big="n"></p>
<input v-bind="n">
directives: {
//简写形式默认在与元素成功绑定时就执行完函数,然后在更新候才会再执行
big(element, binding) {
    element.innerText = binding.value * 10
},
fbind: {
    //指令与元素成功绑定时
    bind(element, binding){
        element.value=binding.value
    },
    //指令所在元素被插入页面时
    inserted(element, binding){
        element.focus()
    },
    //指令所在模板被重新解析时
    updated(element, binding) { 
    },
}
},

全局指令配置:
Vue.directive('指令名',{})/Vue.directive('指令名',function(){})
directives配置里的属性的thiswindowfliter里的也是


生命周期

  • mounted(){}与其他配置同级,挂载完后执行(真实DOM元素放到页面后执行)
  • debugger;在代码里写这个就相当于在此处打了断点
  • 销毁后VueDom绑定的原生事件是还存在的
  • beforeDestory时候数据方法是可以访问修改的,但是不会触发更新

创建组件

  • 定义=>注册=>使用
  • Vue.extend({})
  Vue.component('global',{
     template:`<div><p>{{name}}</p></div>`,
     data(){
         return{
             name:'全局组件global'
         }
     }
  })
  let hello=Vue.extend({
     template:`<div><p>{{name}}</p></div>`,
     data(){
         return{
             name:'组件hello'
         }
     }
  })
 let vm = new Vue({
     el: '#one',
     components:{
        'hello':hello,//
     },
  })

若是组件标签名和组件名一样可以直接简写即'hello':hello直接写成hello

一个单词命名:首字母大小写都可;多个单词命名:用-连接或者每个单词首字母大写(首字母大写这个方法需要脚手架)

创建组件时可以不写Vue.extend()直接组件名={...},这样写在注册组件时,Vue自动执行extend()

还可以给组件配置name属性让他在开发者工具中展示其他名字


组件的嵌套:组件中也有template配置

组件的原理:比如创建一个组件叫hello

  • 组件本质是一个VueComponent构造函数,在调用Vue.extend()时生成并赋值给hello
  • Vue在解析组件时,会创建一个hello实例对象(也就是执行 new VueComponent(option)
  • 每次调用Vue.extend()都会返回一个全新的VueComponent
  • 其实此时hello就相当于Vuehello的实例对象vc就相当于vm,所以this的指向也就不言自知了

组件与Vue的内置关系

黄色线Vue改的,本来是指向Object.prototype


render函数

  • 因为默认引用的vue文件是精简版的,不包含模板解析器,所以不能写template:{},components:{};要用render函数代替
  • render函数的完整写法为
render:function(createElement){
    return createElement(App)
  }
//精简为render:h=>h(App)
>
createElement是函数
>

带runtime的是运行版本vue(没有模板解析器)
带common的是略(不知道)
带esm的意思是es6模块化语法用的


vue.config.js

  • 在这个里面可以配置vue的个性化,具体在vue-cli文档配置中现查现用即可
  • 比如我在vue.config.js中加lintOnSave:false那当我定义一个变量没有使用也不会报错了

ref属性

  • 用来替代id,具体引用如下
<p ref="p" style="opacity:0;">我出现啦</p>
<button @click="showDom">点我</button>
showDom(){
     this.$refs.p.style.opacity='1'
    }
  • 给元素添加ref属性,会出现在实例的$refs属性上keyref值,val是真实Dom元素

如果给组件添加ref属性,会获取到组件实例对象


props配置(子组件配置,父组件赋值)

props的三种写法:

1. props:['属性1','属性2']
2. props:{
    属性1:Number,
    属性2:String
}
3. props:{
    属性1:{
        type:,
        default:,
        required:,//是否必要
    },
    属性2:{}
}

vue不允许改prop值(prop值是只读的),有效果但不允许改,如果要在子组件改,在data中新配置一个参数接受传进来的prop值,改data中的数据

prop也可以实现子组件传递数据给父组件
先在父组件定义一个带参函数
然后把这个函数用prop传递给子组件

然后子组件调用这个函数的时候就可以用传参的方式让父组件得到子组件来的数据


mixin配置

  • 组件之间复用配置
  • 另外创建一个js文件,里面写export default {data(){return{}}},在组件中配置mixin:[mixin]
<p>mixin混入{{num2}}</p>
import mixin from '../mixin'
mixins:[mixin]
mixin.js中写:
export default {
data() {
	return {
		num2:100
	}
},
}

如果组件中有的东西,则采用组件中的;
钩子函数都会采用
Vue.mixin({})全局混入


插件创建与使用

  • 插件是一个对象,写在一个js文件中并导出
import Vue from "vue"
export default {
	install(){
		console.log('用插件啦')
		Vue.filter('guo',function(val){
			return val.slice(0,1)
		})
	}
}
  • 在main.js中使用插件import plugin from './plugins';Vue.use(plugin)
  • 这样Vue就使用了这个插件,在其他组件中就可以使用插件中定义的过滤器,自定义事件…
<p>{{msg | guo}}</p>

scoped

css只控制自己


本地存储localStorage

  • setItem('key','value') 添加一个键值对
  • getItem('key') 获取一个键的值
  • removeItem('key') 删除一个键值对
  • clear() 清除所有

这里面存储对象得是json对象

当对对象增删改查时,可以用监视来向本地存储更新数据,而且最好写完整写法进行深度监视


自定义事件

  • 适用于子传父

绑定

  • 第一种写法:用@绑定事件再用this.$emit('事件名',参数1,参数2...)
父组件中:
<组件标签 @事件名='触发函数'/>...
触发函数(参数){}...
子组件中:
函数(){
  this.$emit('事件名',参数)
}
  • 第二种写法:在mounted钩子中写this.$refs.hello.$on('sendMsg',this.showMsg)绑定事件再用this.$emit('事件名',参数)
//父组件中:
<Hello ref='hello'/>...
  showMsg(msg){
     console.log('Hello的参数来喽',msg)
  }...
mounted() {
    this.$refs.hello.$on('sendMsg',this.showMsg)
  }...

//子组件中:
<button @click="sendMsg">点我把数据传给App</button>
msg:'我来自子组件Hello'
sendMsg(){
      this.$emit('sendMsg',this.msg)
    }

如果mounted中的this.showMsg直接写成了匿名函数,那这个函数的this指向vc

如果写成箭头函数,this指向vm

!!!不建议这样写,建议如上图代码中这样写,先在methods中配置好

当在组件标签中写vue本来就有的事件的时候他会默认为是自定义事件,从而触发失败

这个时候就要用修饰符native来修饰

第二种写法更好,更灵活,因为可以进行延迟,不用一开始就绑定事件导致函数还没准备好而触发失败

一个函数需要接收多个参数,函数(参数1,...params){};//意思是拿第一个参数,其他参数打包在params数组中

也可以用$once绑定一次性事件,也可以用 $on 绑定然后用  once  修饰符绑定一次性事件


解绑$off()

  • $off('')解绑一个自定义事件
  • $off(['','']) 解绑多个自定义事件
  • $off()解绑所有自定义事件

要写在定义自定义事件的组件里,即写$emit的那个组件


全局事件总线$bus

  • $bus是自己命名的,并不是封装好的Api
  • 原理
    • 在两个组件之间找到一个可以用vm各种方法的中间者
    • 一个组件给中间者绑定事件,规定回调
    • 另一个触发事件
  • 代码实现
//main.js中
beforeCreate(){
    // this.__proto__.$bus=this
     Vue.prototype.$bus=this//定义全局事件总线
    
  }
//触发组件中
this.$bus.$emit('bus', this.msg)
//绑定组件中
this.$bus.$on('bus',this.fun)

消息订阅与发布pubsub.js

  • 所有框架适用
  • 使用
    • 安装pubsub.js库:npm i pubsub-js
    • 在接受组件中订阅消息let subId = pubsub.subscribe('消息名',回调函数)
    • 在发送数据组件中发布消息pubsub.publish('消息名',数据)
  • 取消订阅punsub.unsubscribe(subId);

在用了全局事件总线和pubsub后最好在beforedestory钩子里取消事件绑定和订阅


$nextTick

  • 改变代码执行顺序,在一个函数中用它,会让之前的操作做完并重新渲染Dom后再执行它的回调
  • this.$nextTick(回调)

这是一个钩子函数


Vue实现动画

动画写法

<button @click="isShow=!isShow">点我执行动画</button>
<transition appear="true" name="hello">
    <div class="_css" v-show="isShow"></div>
</transition>...

._css{
	background-color: blueviolet;
	height: 50px;
}
.hello-enter-active{
	animation: move 1s linear;
}
.hello-leave-active{
	animation: move 1s linear reverse;
}
@keyframes move {
	from{
		transform: translate(-100%);
	}
	to{
		transform: translate(0px);
	}
}...
  • 如果要给全部的transition标签包裹的元素执行动画则csshello换成v
  • appear默认执行一次

过度写法

<button @click="isShow=!isShow">点我执行动画</button>
<transition appear="true" name="hello2">
    <div class="_css2" v-show="isShow"></div>
</transition>

._css2{
	background-color: blueviolet;
	height: 50px;
	transition: .5s linear;
}
.hello2-enter{
	transform: translate(-100%);
}
.hello2-enter-to{
	transform: translate(0);
}
.hello2-leave{
	transform: translate(0);
}
.hello2-leave-to{
	transform: translate(-100%);
}

多个过度

  • 包裹在一个transition-group标签中

这样写必须给每个子元素一个唯一的key


animate.css库

  • 安装 npm i animate.css
  • 导入import 'animate.css'
  • transition标签配置
    • name="animate__animated animate__bounce"
    • enter-active-class="进入类名"
    • leave-active-class="离开类名"

类名到官网或者css库复制


配置代理

  • vue-cli会自动启动一个代理服务器localhost:8080
    • 这个代理服务器的根文件就是public文件夹
  • vue.config.js文件中开启代理服务器
devServer:{
  proxy:'http://127.0.0.1:8000'
}
  • 开启一个服务器。用express举例
const express = require("express");
  const app = express();
  app.get("/one", (request, response) => {
  response.getHeaders('Access-Control-Allow-Origin','*')
  response.send(student);
  });
  app.listen(8000,()=>{
  console.log('服务器启动')
  })
  • vue组件中用axios请求数据
import axios from 'axios'
  axios.get('http://localhost:8080/one').then(
    response => {
    console.log(response.data)
    },
    error => {
    console.log('请求失败', error.message)
    }
  )

安装axios: npm i axios
express框架使用见ajaxnode基础
❗开启代理服务器后需要重启vue

配置代理完整写法

devServer: {
    proxy: {
      '/msg': {//头标识
        target: 'http://127.0.0.1:8000',//请求路径
        pathRewrite:{'^/msg':''},//把/msg变为空,这样向8000请求的时候就不会是http://127.0.0.1:8000/msg/one了
        ws: true,//略
        changeOrigin: true//服务器是否撒谎,默认撒谎
      },
      '':{}...
    }
  • vue中这样请求 axios.get('http://localhost:8080/msg/one').then()

完整写法可以控制他是否走代理,如果不走代理,就默认给根文件的同名文件


v-resource

  • 了解即可
  • 安装 npm i v-resource
  • 引入 import xxx from 'v-resource'
  • 使用 Vue.use(xxx)
  • 然后this.$http.get()等价与axios.get()
  • resource封装的是xtraxios封装的promise

插槽

默认插槽

  • 子组件中写slot标签
  • 负组件中写插入内容

具名插槽

  • slot标签给个name属性并给值
  • 父组件中写给v-slot指令添加设置好的name
  • 如果是用template标签包裹的可简写v-slot为slot

作用域插槽

  • 因为插槽是在父组件中解析了再插入子组件中,所以就读不到子组件的信息
  • 插槽向父组件传值
    • slot标签绑定数据:msg='data中的数据'
    • 父组件中必须用template标签包裹要插入的内容,并添加属性scope='val'
      • val即是子组件传来的值
    • 使用时{{val.msg}}
<!--子-->
<div>
  <slot :a='回传数据1' :b='回传数据2'></slot>
</div>
<!--父-->
<my>
  <template slot-scop='value'>
    <p :x='value.a' :y='value.b'></p>
  </template>
</my>

slot标签传递过去的是{msg:data中的数据}即val
如果直接用msg别忘了解构赋值


vuex

多个组件共享状态(数据)

原理图

配置环境

  • 安装vuex3版本:npm i vuex@3
  • src目录下新建一个store文件夹,里面新建一个index.js
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
let actions = {};//响应组件中的动作
let mutations = {};//操作state数据
let state = {};//存储数据
let getters = {};//对state中的数据进行加工
export default new Vuex.Store({
  actions,
  mutations,
  state,
  getters,
});
  • main.js中引入store再配置
import store from './store/index'
new Vue({
  render: h => h(App),
  store,
}).$mount("#app");

为什么use不写在main.js里,因为import会先引入store再执行Vue.use(Vuex)

使用

  • 需要用数据的组件中写this.$store.dispatch('actions中的函数名',value)
    • 如果不需要发送ajax之类的,可以直接用this.$store.commit('',xx)直接略过actions
    • {{$store.state.sum}}组件中获取数据
  • 配置文件index.js添加
let actions = {
  add(context, value) {//这里面其实也可以调用dispatch方法来触发其他在actions里的函数
    context.commit("ADD", value);//这里的ADD是mutations中的函数名
  },
};
let mutations = {
  ADD(state, value) {
    state.sum += value;
  },
};
let state = {
	sum:0
};
let getters = {//在组件中用$store.getters.bigSum获取
  bigSum(state) {
    return state.sum*10
  }
}

mutations中的函数最好全部大写

mapState与mapGetters

当在模板中用$store.state.数据,写太多的时候不好

  • 方法一,配置计算属性一个一个定义计算属性
  • 法二,用mapState直接映射
    • mapState({sums:'sum'})计算属性名为sums,值为state中的sum;返回值为{sums(){return ...}}
    • 所以用...语法...mapState({sum:'sum',...})返回值为sum(){}就可以直接写在计算属性的配置里了
    • 数组写法,需要计算属性名与state中的属性名相同
      • ...mapState(['sum'])
<p>{{bigSum}}</p>...
import {mapState,mapGetters} from 'vuex' ...
computed:{
    ...mapGetters({bigSum:'bigSum'})
  },...

mapActions与mapMutations

当用this.$store.dispatch('',),写太多的时候不好

  • mapState直接映射
    • mapAction({adds:'add'})-----方法名为sum,值为state中的sum;返回值为{adds(){这里面会去联系dispatch并传参给它,第一个参数就是'add',第二个要在模板语法里传递}}
    • 所以用...语法...mapActions({adds:'add',...})返回值为adds(){}就可以直接写在methods的配置里了
    • 数组写法,需要方法名与actions中的属性名相同
      • ...mapActions(['add'])
<p>{{bigSum}}</p>...
import {mapActions,mapMutations} from 'vuex' ...
methods:{
    ...mapActions({adds:'add'})
  },...

因为dispatchcommit需要传递参数,所以在模板里传<button @click="adds(step)"></button>

相当于mapActions联系actions,把add函数赋值给adds,所以给adds传递参数,就相当于给actions中的add传递参数

vuex模块化

  • 配置的时候这样写
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
//响应组件中的动作
let one = {
  namespaced:true,
  actions: {
    add(context, value) {
      console.log(value);
      context.commit("add", value);
    },
  },
  //操作state数据
  mutations: {
    add(state, value) {
      state.sum += value;
    },
  },
  //存储数据
  state: {
    sum: 0,
  },
  //对state中的数据进行加工
  getters: {
    bigSum(state) {
      return state.sum * 10;
    },
  },
};
export default new Vuex.Store({
  modules:{
    one,
  }
});

namespaced:true
这个属性必须写,不然找不到

  • 使用
    • 第一种写法(不推荐)
{{bigSum}}
{{one.sum}}
computed:{
    ...mapGetters({bigSum:'one/bigSum'}),//因为控制台中看到getters中有一个one/bigSum的值是bigSum
    ...mapState({one:'one'})//这样得到的是模块化one
    ...mapState({sum:state=>state.one.sum})//这样是模块化的mapState的正确写法
  },

上述state不可以像mapGetter这样写

    • 第二种写法(推荐)
{{bigSum}}
{{sum}}
computed:{
    ...mapGetters('one',['bigSum']),//在getters的one中取bigsum
    ...mapState('one',['sum'])//在state的one中取sum
},
    • 第三种写法(看着办)
//调用方法
add(){
  this.$store.dispatch('one/add',this.step)
}
获取数据
bigSum(){
  this.$store.getters['one/bigSum']
}

nanoid

  • 安装npm -i nanoid
  • 引用import {nanoid} from 'nanoid'
  • nanoid()随机生成一段字符串id

路由

初级使用

  • 安装npm i router@3
  • <router-link to='/..' active-class=''></router-link>当<a></a>
  • <router-view></router-view>
  • 新建router文档中的index.js
import VueRouter from 'vue-router'
import School from '../components/School.vue'
import Student from '../components/Student.vue'
export default new VueRouter({
	routes:[
		{path:'/School',component:School},
		{path:'/Student',component:Student}
	]
})
  • main.js
import Vue from "vue"
import VueRouter from "vue-router"
import route from "./router/inedx"
Vue.use(VueRouter)
new Vue({
  render: h => h(App),
  router: route,
}).$mount("#app")

路由组件最好在src目录新建一个pages目录来存放
每个组件的$route属性值都是关于自己的
每个组件的$router都是一样的且是同一个东西

嵌套路由

  • 配置与使用
routes:[
		{
			path:'/school',
			component:School,
      redirect:'/school/schoolname',//重定向
			children:[
				{path:'schoolname',component:SchoolName},
				{path:'schooladdress',component:SchoolAddress}
			]
		},
		{path:'/student',component:Student},
    {
      path:'*',//打开页面重定向到Home
      component:Home
    }
	]...
  <router-link to="/school/schoolname">SchoolName</router-link>

子路由不写/
使用写全路径

query路由传参

//法一不推荐
<router-link 
      :to="`/school/schoolname?msg=${msg}&a=1`">
</router-link>
//法二推荐
<router-link :to="{
      path:'/school/schooladdress',
      query:{
        msg:msg
        }
      }">
</router-link>
  • 接收
$route.query.msg

命名路由

  • 当要写的路由路径太长才使用
  • 配置
{
  name:'schoolname',
  path:'schoolname',
  component:SchoolName
}
  • 使用
<router-link :to="{
    name:'schooladdress',
    query:{msg:msg}
    }">
</router-link>

params路由传参

  • 配置
//的用:占位符占位
{
  name:'schoolname',
  path:'schoolname/:msg?/:a',//带?是指这个参数可传可不传
  component:SchoolName
},
{
  name:'schooladdress',
  path:'schooladdress/:msg',
  component:SchoolAddress
}
<router-link :to="`/school/schoolname/${msg}/1`">
</router-link>
<router-link :to="{
    name:'schooladdress',
    params:{msg:msg}}">
</router-link>
  • 接收
$route.params.msg

❗❗❗
如果用params传递参数且用to的对象式写法,必须用name,不能用path

  1. params占位乐但是不传,那浏览器导航栏里的路径会出错,但是页面还是能跳转,刷新后就不能跳转了
  2. params传递空串也会导致与1同样问题,可以在配置的时候写params:{
    data:‘’||undefinded
    }

props传参数

  • 在配置中给组件传递固定数据,对象传递,query不行
//路由配置
{
  name:'schoolname',
  path:'schoolname/:msg/:a',
  component:SchoolName,
  props:{
    msg:'prop传递参数',
  }
},
//组件中接收
props:['msg']
//使用
{{msg}}
  • 第二种传法
//子路由配置
{
  name:'schoolname',
  path:'schoolname/:msg/:a',
  component:SchoolName,
  props:true
},
//父传递参数
<router-link :to="{name:'schooladdress',params:{msg:msg}}"><router-link>
//子组件中接收
props:['msg']
//子使用
{{msg}}

这样会把所有params参数以props的形式传递过去,使用时就不用$route.params.msg
但是此方法不适用与于query

  • 函数传递(推荐)
//路由配置
{
  name:'schoolname',
  path:'schoolname/:msg/:a',
  component:SchoolName,
  props($route){
    return {msg:$route.params.msg}//params也可以是query。具体看点击时传递方式
  }
},
//组件中接收
props:['msg']
//使用
{{msg}}

router-link的replace属性

替换当前浏览器纪录,默认为追加push

<!-- 1 -->
<router-link :replace='true'></router-link>
<!-- 2 -->
<router-link replace></router-link>

编程式路由导航

  • $routerapi
    • push({}){}里的配置就和:to"{}"中的一样;追加记录
    • replace({})同上;替代记录
    • back()后退
    • forward()前进
    • go(2/-2)前进/后退2步

push({},()=>{},(error)={})完整长这样

push()会返回东西,不写回调会有警告,可重写push方法来一劳永逸

//./router/index.js
//重写push
let originPush = VueRouter.prototype.push
VueRouter.prototype.push = function (location, reslove, reject) {
	if (reslove && reject) {
		originPush.call(this, location, reslove, reject)
	} else {
		originPush.call(this, location, () => { }, () => { })
	}
}
//重写replace
let originReplace = VueRouter.prototype.replace
VueRouter.prototype.replace = function (location, reslove, reject) {
	if (reslove && reject) {
		originReplace.call(this, location, reslove, reject)
	} else {
		originReplace.call(this, location, () => { }, () => { })
	}
}
goHere(){
  this.$router.push({
    name:'schooladdress',
    params:{msg:this.msg}//如果这里msg为'',路径会出错;要写成params:{msg:''||undefine}
  })
}

缓存路由组件

  • 使路由跳转时组件不销毁
    • 比如组件内有input有内容,那么切换去其他组件再切换回来input内容不消失
  • include的值为需要保留的组件name值;如果保留全部就不用写;如果保留多个:include="['','','']"
<!--在父组件中-->
<keep-alive include="SchoolName">
  <router-view class="view_1"></router-view>
</keep-alive>

activated与deactivated

当一个组件内有input且组件内有定时器等不需要缓存的东西,就可以在deactivated生命周期中消除,这样组件能在不被销毁的同时缓存需要的东西

  • 两个钩子函数
  • activated在组件激活时被触发
  • deactivated在组件失活时触发

路由守卫

全局前置路由
  • 路由配置中配置
router.beforeEach((to, from, next) => {
	to//目标路径
  from//从哪个路径离开
  next()//写了代表允许,不写代表不允许
	if(to.path==='/school/schoolname/我来自组件School/1'|| to.name==='schooladdress'){
		if(localStorage.getItem('passWord')==='666'){
			alert('没有权限')
		}
	}else{
		next()
	}
})
export default router

路径中有参数的话,编译完成的路径才是to或者frompath
❗ 也可以不用比较path或者name,可以给已经知道需要守卫的路由配置一个值来判断是否需要验证
❗ 但是配置中不允许随便给属性,所以写在一个属性meta里,这个是专门给程序员自己定义数据用的,在$route里可以看见

{
	name:'schoolname',
	path:'schoolname/:msg/:a',
	component:SchoolName,
  meta:{//路由元信息
    is:true
  }
},

全局后置路由
  • 路由配置中配置
router.afterEach((to, from) => {
	to//目标路径
  from//从哪个路径离开
  document.title=to.meta.title
})
export default router

独享前置路由守卫
{
  path:'/school',
  component:School,
  beforeEnter(to,from,next){
},

没有独享后置路由

组件内的守卫
  1. 通过路由规则进入才会调用,直接使用<组件名/>不会调用
  2. mounted配置同级
  • beforeRouterEnter(to,from.next){}
    • 进入组件后调用给❓(可能理解错了)
  • afterRouterEnter(to,from.next){}
    • 从此组件跳去其他组件后调用❓(可能理解错了)
  • 使用
    • 在组件里用,本质是钩子函数

路由守卫执行顺序

  • 导航被触发。
  • 在失活的组件里调用 beforeRouteLeave 守卫。
  • 调用全局的 beforeEach 守卫。
  • 在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
  • 在路由配置里调用 beforeEnter
  • 解析异步路由组件。
  • 在被激活的组件里调用 beforeRouteEnter
  • 调用全局的 beforeResolve 守卫(2.5+)。
  • 导航被确认。
  • 调用全局的 afterEach 钩子。
  • 触发 DOM 更新。
  • 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

简单来说就是:beforeRouteLeave–>beforeEach–>beforeEnter–>beforeRouteEnter–>afterEach–>DOM更新–>beforeRouteEnter的next

全局前置-独享-组件内进入-全局后置-组件内离开

路由懒加载

  1. 语法import('url')返回的是promise对象
  2. 所以可以在注册组件时候让组件的值为promise对象,底层代码在遇到promise对象时会去取成功的值,具体实现源码见
  3. 在用户访问组件时才会加载
path: '/pay',
component: () => import('@/pages/Pay'),
meta: {
	isShow: false 
}

vue的两种工作模式

  • hash带#
  • history不带#
  • 不是很懂

Vue项目打包

  • npm run build

element-ui入门

  • 文档自查使用

!
babel.config.js中的presets配置项改为

presets: [
  '@vue/cli-plugin-babel/preset',
    ["@babel/preset-env", { "modules": false }]
],

其他

  1. v-module原理
<input :value="msg" @input="msg = $event.target.value">
  1. 自定义事件中的$event
<!--子组件-->
<input :value="msg" @input="$emit('input',$event.target.value)">
<!--父组件-->
<!--在自定义事件中,$event是传递过来的数据-->
<my @input='msg = $event'></my>
  1. 修饰符sync语法糖
    同步父子数据
<!--子组件-->
<input :value="msg" @input="$emit('update:msg',$event.target.value)">
<!--父组件-->
<!--.sync就相当于为这个组件绑定了一个自定义事件叫(update:msg)
    且update:msg为固定名称写法,唯一变数是msg,它是data中的数据
-->
<home-1 :msg.sync='msg'></home-1>
  1. a t t r s 与 attrs与 attrslisteners
    1. $attrs 能获取到父组件传递来的 prop 参数
    2. $listeners 能获取到父组件传来的自定义事件
    3. 应用:比如二次封装element-ui组件,用传递prop,$attrs接收的形式改变组件样式
<!--父组件-->
<home-2 a='1' b='2' c='3'></home-2>

<!--子组件-->
<p>{{a}}-{{b}}-{{c}}-{{$attrs}}</p>
<p v-bind='$attrs'>v-bind直接绑定多个属性</p>
<script>
export default {
  name: 'home-2',
  props:['a','b'],
}
</script>
<!--输出:1-2--{ "c": "3" }-->
<!--$attrs能获取到父组件传递来的prop参数
    并且在子组件prop配置接收了的prop参数,$attrs是接收不到的
    v-bind='{"name":"xz","age":"19"}这样可以一次绑定多个属性'
-->
  1. c h i l d r e n 与 children与 childrenparent
  2. $children获取当前组件的所有子组件,类型为数组
  3. $parent获取当前组件父组件(❓有多个父组件我没试过。。。)

各种报错解决集

  1. 关闭组件命名规则
  2. 关闭html中报错clear
package.json中
"eslintConfig": {
  "rules": {
    "vue/comment-directive": "off",//关闭html中报错clear
    "vue/multi-word-component-names":"off"//关闭组件命名规则
  }
},
  1. 模块化getters的形参state,是$store下的一级state
  2. 给组件添加dom原生事件
<!-- 这样写vue会默认click是自定义事件 -->
<my @click='fun'></my>
<!-- 这样写click是dom原生事件 -->
<my @click.native='fun'></my>

常用包

  1. Lodash防抖节流…
  2. mockjs生成随机数据
  3. swiper轮播图库
  4. uuid随机生成id
  5. qrcode将文本生成二维码
  6. vue-lazyload图片懒加载
  7. vee-validate表单验证(烂)
Logo

前往低代码交流专区

更多推荐