vue插值语法
v-html: 用于解析带html标签时的字符串数据
v-pre: 原封不动的输入{{msg}}不会进行编译,比如:<p "v-pre>{{msg}}</p> => {{msg}}"
v-once: 只编译一次,当绑定数据再次发生改变,不会跟着改变
-
v-cloak: 当js执行完毕之前页面会先输出template中的{{}}内容,这种情况对用户体验不好,该指令可以在js执行完之后渲染{{}}内容,执行前不会显示。
原理:解析前标签中加v-cloak属性,此时该属性display:none, 解析后标签取消该属性,display 消失就会显示出内容
<template> <h2 v-cloak>{{msg}}</h2> </template> <style> [v-cloak] { display: none } </style>
v-text: 把变量以指令的方式解析,不够灵活不推荐使用
vue绑定 v-bind
属性绑定 绑定样式的三种方式
1. 直接绑定样式:需要在data中定义该类名 <h4 :class="active"><h4>
2. 对象的方式绑定,可以绑定多个:<h4 :class="{类名:boolean,类名:布尔值}"><h4>
3. 数组的方式,可以绑定多个:<h4 :class="[类名1,类名2]"><h4>
style绑定
<h4 :style={属性名:属性值}><h4> => <h4 :style={fontSize: '100px',color: 'red'}></h4>
vue 手动获取event对象
<button @click="getEvent('参数1',$event)">
获取event
</button>
1. 当方法没有参数时可以省略括号,默认会传event对象
2. 当有其他参数时,获取event对象需要用$event
vue事件修饰符
@click.修饰符=“method”
1.prevent: 阻止默认事件,比如 a标签默认跳转
2. stop: 阻止事件冒泡
3. once: 绑定事件只触发一次,再次无效
4. self: 只有event.target是当前操作的元素时才触发事件(也就是说是绑定的该元素本身被点击了才会触发)
5. capture: 事件捕获时触发事件
6. passive: 事件的默认行为立即执行,无需等待事件回调完成
vue键盘事件
@keyup="method" || @keydown="method"(keyup按下并放松才会触发,keydown按下就会触发)
键盘事件修饰符:
1. enter 2. esc 3. shift 4.ctrl 5.....等等
组合使用:@keyup.ctrl.y 必须同时按下ctrl+y才能触发
vue watch(事件监听)
new Vue({
data: {
numbers:{
a:1,
b:2
},
name:'皎月'
},
// vue实例可以监测到复杂对象内部变化,但是watch只能监测一层
watch: {
numbers: {
deep:true, // 开启深度监听,默认watch只能监听一层数据,要监听复杂类型需要开启深度监听
handler(newVlaue,oldValue){
console.log('我被改变了')
}
}
},
// 如果监听的数据格式简单,不需要深度监听,可以简写成下面方式
watch:{
name(newVlaue,oldValue){
console.log('监听简单数据,简写方式')
}
}
})
vue中的key(原理)
1. 虚拟dom中key的作用:
key是虚拟dom中对象的标识,当数据发生改变时,vue 会根据新数据生成新的虚拟dom,然后进行虚拟dom的对比,比较规则如下:
-
旧的虚拟dom中找到和新的虚拟dom相同的key:
- 比较虚拟dom元素是否相同,如果不相同就生成新的真实dom,并且替换之前旧的dom。
- 如果虚拟dom相同,直接拿旧的真实dom进行复用。
-
旧的虚拟dom中没有找到和新的虚拟dom相同的key:
- 直接创建新的真实dom,并且渲染到页面。
-
如果用index当做key可能引发的问题
- 对数据进行逆序添加、删除等破坏顺序的行为时,会导致dom重复更新,效率低。
- 如果dom中包含输入类的标签,会导致错误的dom更新,导致界面出现问题。
-
不添加key会发生什么
- 默认如果没有加key vue默认会用index当做key来使用。
- 严格模式下,编译会报警告。
vue中的过滤器
过滤器filter
1. 假如data中有一个属性date:12343000,把date格式化成2021-7-16这种格式。
<h3>{{time | timeFormarter}}</h3>
2. 过滤器可以传递参数,第一个参数固定是过滤器前的值,第二个参数才是过滤器格式参数。
<h3>{{time | timeFormarter('YYYY-MM')}}</h3>
3. 过滤器可以串联写多个,第三个过滤器的值是第二个过滤器返回的结果,假如有多个以此类推。
<h3>{{time | timeFormarter('YYYY-MM') | myFilter}}</h3>
--->vue中写过滤器
filters:{
timeFormarter(value,str){
return datejs(value).formart(str)
},
myFilter(value) {
}
}
vue 自定义指令
<h3 v-big="n"></h3>
new Vue({
data:{
n:10
},
directives: {
big(element,binding){
// element 指令绑定dom binding对象里面有传入的值和指令信息
// ...进行指令要执行的代码逻辑
}
}
})
vue props接收的三种方式
1. 简单接收
// 组件传值
<School name="张三" age="18" sex="男"></School>
export default {
props: ['name','age','sex']
}
2. 接收同时限制类型
// 组件传值
<School name="张三" :age="18" sex="男"></School>
// age前加: 会把age解析成表达式数字类型18,否则会是字符串“18”
export default {
props: {
name: String,
age: Number,
sex: String
}
}
3.接收的同时限制类型,并且给没传的属性默认值
// 组件传值
<School name="张三" sex="男"></School>
export default {
props: {
name: {
type: String, // 接收值的类型
required: true // 接收的必传
},
age: {
type: Number,
default: 88 // 默认值,不传age则为88
}
}
}
4.备注
组件解析是props优先级比较高,会先解析props在解析组件中的data数据
vue (mixin混入的使用)
1、局部混入
// 可以把组件中的配置项比如data/methods/生命周期等写入一个公共的文件,那个组件要使用,就去引入叫做混入,实现配置项的复用
// 1. 创建一个第三方文件 mixins.js
export const mixin1 = {
data(){
name: '张三',
age: 24
}
}
export const mixin2 = {
methods: {
showName() {
alert(this.name)
}
}
}
// 2.在需要混入的文件中引入,并且声明
import {mixin1, mixin2} from './mixins.js'
export defalut {
mixins: [mixin1, mixin2]
}
2.全局引入(不推荐使用)
// 在main.js中引入mixins.js
import {mixin1, mixin2} from './mixins.js'
Vue.mixin(mixin1);
Vue.mixin(mixin2);
3.备注
1.混入的如果是data()/methods和组件内冲突,以组件中的为主
2. 混入的如果是生命周期钩子,那么混入的和组件内的都会执行,并且混入的会先执行,组件内后执行
vue 自定义事件
定义自定义事件两种方式:
1. <School @getSchoolName="getName"></School>
2. <School ref="school"></School>
// 组件方法
methods: {
getName(name) {
console.log(name)
}
}
// 组件钩子函数
mounted() {
this.$refs.school.$on("getSchoolName",this.getName)
}
// 子组件触发自定义函数需要用到$emit方法
this.$emit("getSchoolName",this.name)
备注
- 如果自定义方式只需要触发一次就失效需要加上once修饰符
<School @getSchoolName.once="getName"></School>
orthis.$refs.school.$once("getSchoolName",this.getName)
- ** 如果要在子组件上绑定原生的js事件,需要加上native修饰符否则不生效 **
<School @click.native="getName"></School>
自定义事件解绑:
-
this.$off("事件名")
解绑一个事件 -
this.$off(['事件名1','事件名2'])
解绑多个事件
vue 全局事件总线
1.定义全局事件总线
// main.js
import Vue from 'vue'
import App from 'App'
new Vue({
el:'#app',
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this
}
})
2.使用事件总线传递参数
// 在需要接受的组件内绑定监听事件
mounted(name) {
this.$bus.$on("getName", (name) =>{
// 回调函数
console.log(name)
})
}
// 在需要传递参数的组件内发射事件
methods: {
handler() {
this.$bus.$emit("getName", this.name)
}
}
备注:
在监听事件的组件中,最好记得解绑监听的事件,因为$bus是定义在vue原型上最好组件销毁之前手动解绑监听事件
beforeDestory() {
`this.$bus.$off("getName")`
}
消息订阅与发布(pubsub-js)
1. 安装中间件 npm i pubsub-js -S
2.引入使用
import pubsub from 'pubsub-js'
// 订阅一个消息
// msgName: 事件名称 data:传递的参数
pubsub.subscribe("hello",(msgName, data) => {
// 回调事件
})
// 发布一个事件
pubsub.publish("hello", this.name)
vue跨域配置代理的方式
1.cors(需要后端配置)
2.jsonp(通过script Src属性请求脚本,缺点:只支持get请求)
3. nginx 配合跨域
4. vue-cli配置代理
// 通过cli配置代理需要在vue.config.js中配置选项
module.exports = {
devServer: {
"proxy": {
"/api": {
target: 'url', //目标服务器路径
changeOrigin: true, //为true时ajax请求的url和服务器一致,为false时ajax请求的url是真实的主机地址, 默认为true
pathRewrite: {'^/api': '' }, // 请求服务器资源替换api为空
}
}
}
}
vue 插槽
1. 插槽的作用:适用于父组件往子组件中传递结构 父组件>>>子组件
2.插槽的分类: 默认插槽 、具名插槽、作用域插槽
父组件:
<template>
<Category>
<h4>我的默认插槽的内容</h4>
</Category>
</template>
子组件:
<template>
<slot>默认插槽</slot>
</template>
---------------------------------------------------------------------
父组件:
<template>
<Category>
<--写法1-->
<h4 slot="top">我的具名插槽的内容</h4>
<h4 slot="bottom">我的具名插槽的内容</h4>
<--写法2-->
<template v-slot:bottom>
<h4>我的具名插槽的内容</h4>
</template>
</Category>
</template>
子组件:
<template>
<slot name="top">我是顶部内容</slot>
<slot name="bottom">我是底部内容</slot>
</template>
3.作用域插槽
// 作用域插槽适用于,数据在子组件中,如果展示数据的结构在父组件中定义,子组件>>>父组件
父组件:
<template>
<Category>
<--写法1-->
<template scope="data">
<h4 v-for="(item,index) in data.cates">{{item}}</h4>
</template>
<--写法2-->
<template slot-scope="data">
<h4 v-for="(item,index) in data.cates">{{item}}</h4>
</template>
</Category>
</template>
子组件:
<template>
<slot :cates="cates">我是作用域插槽</slot>
</template>
data() {
return{
cates: ['热门','新闻','政治']
}
}
vuex使用
当有多个组件需要共享一个状态时候,就可以使用vuex来管理那个共享状态
1.安装vuex
npm i vuex -S
2. 在src下创建store文件夹(创建store仓库)
// store下的index.js
import Vue from 'vue'
import Vuex from 'vuex'
// 挂载vuex
Vue.use(Vuex)
// vuex核心 三大模块内容actins, mutations, state 皆是一个对象
// 1.actions: 通常用于和组件实例的交互行为,通俗的讲就是接收组件实例中dispatch分发的方法,然后commit一个mutations,在actions中可以执行一些异步任务
const actions = {
// context: 上下文对象,里面包含commit,dispatch等
// value: 组件实例调用方法时传的参数
increment(context, value) {
// 提交一个mutations
context.commit('INCREMENT', value)
}
},
// 2.mutations: 用于改变state中状态
const mutations = {
// state: 状态管理对象
// value: actions提交时传递的参数
INCREMENT(state, value) {
state.sum += value
}
},
// 3. state: 管理共享数据的仓库
const state = {
sum: 0
}
// 4. getters: 相当于组件中的computed,如果state中的某个状态需要加工后返回可以使用,getters必须有返回值
const getters = {
doubleSum(state) {
return state.sum * 2
}
}
// 导出store仓库
export default new Vuex.Store({
actions,
mutations,
state,
getters
})
3. 在main.js引入store仓库挂载到组件实例对象上
// main.js
import Vue from 'vue'
import App from 'App'
import store from './store'
new Vue({
el:'#app',
store,
render: h => h(App)
})
4. 组件中如何使用vuex中的state?
// a.vue组件
//1. 访问vuex管理的数据 借助vuex中mapState方法
import { mapState, mapGetters } from 'vuex'
// 2.在计算属性中获取
export default {
computed() {
// 对象的简写形式
// mapState函数实际上就是返回一个计算属性,number就是template中使用的值,sum对应state中状态数据
...mapState({number: 'sum'})
// 数据的简写形式
//使用数组简写时,实际上就是{sum: 'sum'},要求state中的数据必须是sum,在template使用是也是sum
...mapState(['sum'])
}
}
// mapGetters 使用方法和上面一致
5.组件中如何使用vuex中的actions和mutations?
// a.vue组件
//1. 使用vuex管理actions 借助vuex中mapActions方法
import { mapActions, mapMutations } from 'vuex'
// 2.在methods属性中获取
export default {
methods() {
// 对象的简写形式
// mapActions add就是template中使用的方法名,increment对应actions中方法
...mapActions({add: 'increment'})
// 数据的简写形式
//使用数组简写时,实际上就是{increment: 'increment'},要求actions中必须是increment,在template使用是也是increment
...mapActions(['increment'])
}
}
// mapMutations 使用方法和上面一致
vuex模块化
// store/count/index.js
// 模块一
export const count = {
namespaced: true, // 使用模块化必须开启命名空间
actions: {},
mutations: {},
state: {},
}
// store/person/index.js
// 模块二
export const person = {
namespaced: true, // 使用模块化必须开启命名空间
actions: {},
mutations: {},
state: {},
}
// store/index.js
import {count} from './count'
import {person} from './count'
export default new Vuex.Store({
modules: {
count,// 模块化名
person // 模块化名
}
})
使用模块化
// 组件中
import { mapState, mapActions } from 'vuex'
export default {
computed() {
// mapState接收两个参数
// 第一个:count是模块名
// 第二个: sum是count模块中state中定义的数据名
...mapState('count', ['sum'])
// 直接读取的方式
// this.$store.count.sum
},
methods: {
// mapActions接收两个参数
// 第一个:person是模块名
// 第二个: add是person中actions中定义的方法名
...mapActions('person', ['add'])
// 第二种写法 person/add:模块/方法名 2: 参数
//this.$store.dispatch('person/add', 2)
}
}