指令
内容渲染
-
v-text
- 覆盖内部原有内容
-
{{}}
- 内容占位
-
v-html
- 渲染成HTML
属性绑定
-
v-bind(:)
- 动态绑定值(单向)
事件绑定
-
v-on:可简写为@
-
v-on
-
事件对象
-
@click=“clk(666,$event)”
- 自动给形参$event传入事件对象
-
-
事件修饰符
-
@click.prevent
- 阻止单击默认行为
-
@click.stop
- 阻止单击冒泡
-
-
按键修饰符
-
@keyup.enter
- enter键抬起
-
@keyup.esc
- esc键抬起
-
-
双向绑定
-
v-model
-
动态绑定值(双向)
-
绑定修饰符
-
转为数值
- v-model.number
-
去掉首尾空白
- v-model.trim
-
懒更新
- v-model.lazy
- 输入完成后更新数据
-
-
条件渲染
-
v-if、v-else-if、v-else、
- 对dom修改
-
v-show
- 对css修改
列表渲染
绑定key
- v-for
插槽绑定
v-slot: 简写 #
v-slot:槽名 简写为 #槽名
自定义指令
this = undefined
vue指令规定必须以v-开头,v-后才是真正的指令名
注意是指令不是属性,指令上下文默认在vue实例上,不需要进行绑定
私有
定义在vue实例的directives节点下
不接收指令值
注意!!!! bind先于mounted this指undefined
<template>
<div>
<p v-color></p>
</div>
</template>
<script>
export default {
directives:{
color:{ // color:指令名
bind(el){ // bind:绑定时执行 el:原生dom对象
console.log(el)
},
update(el){ //update:dom更新时执行,绑定时不执行 数据改变dom改变
console.log(el)
}
}
}
}
</script>
接收指令值
<template>
<div>
<p v-color="red"></p>
</div>
</template>
<script>
export default {
data() {
return {
age:13
}
},
directives:{
color:{ // color:指令名
bind(el,binding){ // bind:绑定时执行 el:原生dom对象
console.log(el,binding.value) // binding.value:指令值
},
update(el,binding){ //update:dom更新时执行,绑定时不执行
console.log(el,binding.value)
}
}
}
}
</script>
bind在绑定时,update在dom更新时执行。每次都执行相同的操作可以将指令名写成函数的形式
<template>
<div>
<p v-color="red"></p>
</div>
</template>
<script>
export default {
data() {
return {
age:13
}
},
directives:{
color(el,binding){ // color:指令名
}
}
}
</script>
全局
通过Vue构造函数的directive()声明
过滤器(filters)
Vue.directive("color",(el,binding){ // Vue.directive(参数1,参数2) 参数2效果同私有指令相同。函数形式每次执行相同的代码 对象形式需指定bind、update
})
vue3(不支持)
一般用于对数据格式化,以 (表达式 | 过滤器)形式调用 。
私有过滤器
定义在Vue实例filters节点下
filters:{
filter(value){
}
}
全局过滤器
调用Vue构造函数的filter函数,传入过滤器名和回调函数
侦听器(watch)
定义在Vue实例watch节点下
方法形式
页面加载时不触发
watch:{
// attribute:要监听的属性 变化后newVal 变化前oloVal
attribute(newVal,oloVal){
}
}
对象形式
页面加载时触发、深度监听
watch:{
// attribute:要监听的属性 变化后newVal 变化前oloVal
attribute:{
handler(newVal,oloVal){
},
// true:页面加载时触发 false:页面加载时不触发(默认)
immediate:true,
// true:开启深度监听 对象属性变化时 会触发(获取到对象非对象属性) false(默认)
deep:true
}
}
监听子属性
要监听对象的子属性,需要给侦听器名加一层单引号
watch:{
// attribute:要监听的属性 变化后newVal 变化前oloVal
'attribute.attribute'(newVal,oloVal){
}
}
计算属性(computed)
定义在Vue实例computed节点下
计算属性也是Vue实例属性,但该属性由计算而来
computed:{
// attribute:计算属性名
attribute(){
// calculate:计算后的值
return calculate
}
}
组件
组件三部分:组件结构(template)、组件行为(script)、组件样式(style)
每个template只能必须包含一个标签
启用less
<style lang="less">
</style>
导入使用
导入
import Left from "@/components/Left.vue"
注册
定义在Vue实例components节点下
components:{
Left
}
导入(全局)
在main.js入口文件导入
import Left from "@/components/Left.vue"
注册(全局)
在main.js入口文件通过Vue.component()注册
Vue.component(“Left”,Left)
使用
<Left></Left>
props(只读)
自定义属性也是实例属性,定义在Vue实例props节点下
用于组件接收外部传入的值
定义(数组)
只能接收值
export default {
props:["attribute"]
}
定义(对象)
指定默认值、类型、必填
export default {
props:{
attribute:{
default:0, //设置默认值
type:Number, //指定类型
required:true //属性必填
}
}
}
使用
<Left attribute1="666"></Left>
样式冲突
scoped
给style加上scoped,实现样式隔离(给所有的元素和样式添加属性data-v-xxx)
<style scoped>
</style>
/deep/
在设置scoped情况下,表示当前组件的属性(data-v-xxx),实现修改子组件样式
<style scoped>
// 可以选择到子组件下的div
/deep/ div{
}
</style>
生命周期
创建
beforeCreate
- 创建前
- 初始化事件和生命周期函数
- 组件的props、data、methods未创建,不可用
created
- 创建后
- 组件的props、data、methods以创建,可用
- 模板结构未生成,dom未创建,不可用
- 用于发送请求
beforeMount
- 挂载前
- 将要渲染,dom未渲染,不可用
mounted
- 挂载后
- dom渲染完成,dom可用
运行
数据更新会引发dom更新,执行0次多次
beforeUpdate
- dom更新前
- 数据以更新,dom未更新
updated
- dom更新后
- 数据、dom更新完成
激活
activated
- 组件在被keep-alive 激活后触发
暂停
deactivated
- 组件被keep-alive 停用缓存后触发
出错
errorCaptured
- 子组件出错(同步错误)会调用这个生命周期函数
销毁
beforeDestroy
- 销毁前
- 将要销毁组件,组件能正常工作
destroyed
- 销毁后
- vue实例销毁完成
父向子传值
props
子向父传值
自定义事件
子组件向外抛出一个自定义事件并传入参数,父组件捕获事件获取参数
子组件
this.$emit("event",data) // 向外抛出一个event自定义事件,传入data
父组件
<son @event="getData"></sonson> // 监听子组件的event自定义事件,调用getData回调
兄弟组件传值
EventBus
通过导入vue实例(单例),触发和监听自定义到达传值和取值的目的
eventBus .js
import Vue from 'vue'
const eventBus = new Vue()
export default eventBus
A .vue
<template>
<div>
<button @click="send">点击发送</button>
</div>
</template>
<script>
import eventBusVue from "./eventBus.js"
export default {
methods:{
send(){
eventBusVue.$emit("send",0)
}
}
}
</script>
B .vue
<template>
<div>
</div>
</template>
<script>
import eventBusVue from "./eventBus.js"
export default {
created(){
eventBusVue.$on("send",(v)=>{
console.log(v)
})
}
}
</script>
App .vue
<template>
<div>
<button @click="send">点击发送</button>
</div>
</template>
<script>
import eventBusVue from "./eventBus.js"
export default {
methods:{
send(){
eventBusVue.$emit("send",0)
}
}
}
</script>
ref引用
每个vue组件实例上,都包含一个$refs对象,存储这对dom元素或组件的引用。默认属性为空
<son ref="s"></son>
export default {
mounted() {
console.log(this.$refs)
}
}
$nextTick延迟
延迟到dom渲染后执行
this.$nextTick(()=>{
})
name
在声明时给组件指定name,有以下作用
- 在调试工具以name给组件命名
- keep-alive的include以name为准。
插槽
把组件不确定的部分定义为插槽
不具名槽
<slot></slot>
vue官方规定每个slot槽都要有name名称,默认为“default”。
所有的插默认放在name=“default”槽中
具名槽
槽自定义name(不为default)
<slot name="zs"></slot>
插指定槽时必须用template包裹,并且在template上用 v-solt:槽名 指定槽
槽默认内容
当没有插与槽匹配时,可以给槽指定默认内容
<slot name="zs">默认内容</slot>
作用域插槽
可以给槽像一般组件一样传递参数
<slot name="zs" :m="s">默认内容</slot>
插接收参数,必须在template上通过 ="对象名" 来接收槽的参数,默认为空对象,可解构接收,但该对象的作用域只在该template有效
<template v-slot:zs ="ob" > //v-slot: 简写 #,#zs也是可以的
<div>
66
</div>
</template>
不具名插
// 不具名插不用template包裹,默认将内容放到 不具名槽(name="default")中
<Left>
<p>
123
</p>
</Left>
具名插
// 具名插要用template包裹,template是个虚拟元素
<template v-slot:zs ="ob" > //v-slot: 简写 #,#zs也是可以的
<div> // 将template包裹的元素渲染到 name="zs" 的槽处
66
</div>
</template>
动态组件
动态组件可以动态的切换组件的显示和隐藏
vue提供了内置组件,用于实现动态组件
<component is="组件名"></component> //渲染指定组件 切换组件名会导致组件创建销毁
缓存
切换组件时,不会销毁组件,只是将组件隐蔽
<keep-alive>
<component is="组件名"></component> //渲染指定组件 切换组件名不会导致组件创建销毁
</keep-alive>
激活后自动调用组件activated生命周期函数
隐蔽后自动调用组件deactivated生命周期函数
指定缓存
给的include属性添加规则,可以指定被缓存的组件
<keep-alive include=“a”>
<component is="组件名"></component> //渲染指定组件 切换组件时只有a组件不会被销毁
</keep-alive>
mixin(混入)
将相同的部分抽离成一个文件,需要时直接引入使用
组件定义的方法和data等会覆盖混入的
组件的生命周期不会覆盖混入的,混入生命周期先于组件定义的生命周期执行
src/mixin.js
export default { // 向外暴露带有vue格式的对象
data(){
return {
name:'zs'
}
},
mounted(){
console.log("mounted");
}
}
全局混入
root根组件也会被混入,所有vue实例(包括root)都会被混入
main.js
import Mymixin from "./mixin";
Vue.mixin(Mymixin)
局部混入
import Mymixin from "../mixin"
export default {
data() {
return {
h:"123"
}
},
mounted(){
console.log("object");
},
mixins:[Mymixin], // mixins混入只能是数组形式
}
路由
两种模式hash和history(切换url目录,如果用户刷新将向服务器发起请求,存在服务器没有响应的可能)
用户点击路由链接,导致url的hash变化,前端路由监听hash变化匹配不同的组件
安装vue-router
npm i vue-router -S
创建路由模块
- 在src源代码目录下,新建router/index.js
// 导包
import Vue from 'vue'
import VueRouter from 'vue-router'
// 导入组件
import Home from '@/components/Home.vue'
// 在Vue上安装VueRouter插件
Vue.use(VueRouter)
// 创建实例配置路由规则并默认导出
const router = new VueRouter({
mode: "hash", // 默认hash模式 mode: "history"开启请求路径模式
routes:[
{path:'/home',name:'home',component:Home} // 规则里面的name和<router-view name='home'>的name是两个不同的概念,不要混淆
]
})
export default router
导入并挂载路由模块
-
在main.js(打包入口文件)中挂载VueRouter实例
// 导入VueRouter实例 import router from 'router/index.js' new Vue({ router, // 挂载路由实例到Vue实例 store, render: h => h(App) }).$mount('#app')
声明链接和占位符
-
在要跳转路由和要展示的区域使用router-link和router-view
<router-link to="/home">home</router-link> // 可用<a href='#/home'></a>标签修改hash实现 <router-view ></router-view>
路由规则
重定向
redirect
const router = new VueRouter({
routes:[
{path:'/',name:'home',redirect:'/home'} // 将/重定向到/home
]
})
嵌套路由
const router = new VueRouter({
routes:[
{
path:'/home',
name:'home',component:Home,
children:[
{
path:'tab1',
component:Tab1
}
]
}
]
})
默认子路由
const router = new VueRouter({
routes:[
{
path:'/home',
name:'home',component:Home,
children:[
{
path:'', // 子路由path为空,当hash为#/home 时子路由也会匹配
component:Tab1
}
]
}
]
})
路由参数获取
把hash地址可变的部分定义为参数项,提高路由规则的复用性。
在路由匹配规则里面,使用 :变量名 接收参数
const router = new VueRouter({
routes:[
{path:'/home/:id',name:'home',component:Home} // #/home/xxx的内容都被匹配,#/home/xxx/xxx不会被匹配,并且只匹配第一个满足项(书写顺序)
// 在组件里面可以通过 this.$route.params.id获取路由规则里面的值
]
})
route获取
Vue挂载Vue-router后在Vue实例上
this.$route.fullPath:#后的全部字符串
this.$route:路径相关信息
this.$route.params:动态参数对象
this.$route.path:路径参数
this.$route.query:请求参数
在组件里面可以通过 this.$route.params.id获取路由规则里面的值
props获取
const router = new VueRouter({
routes:[
{
path:'/home/:name/:age',
name:'home', // 路由命名
component:Home,
props:true, // 开启props传参,动态params参数会传递给组件对应的porps
props:($route)=>({params:$route.params,query:$route.query}), // 开启props传参,params和query都可以传递porps
}
]
})
参数传递
query
params
注意
通过
path:'/home/:name/:age' // 必须传递对应的参数
path:'/home/:name/:age?' // 可不传
params传递空串路径出问题,传undefined不会
mate
传递格式
字符串
对象
对象的name何必和组件的name保持一致
path不能和params参数一起使用
this.$router.push({name:"demo",params:{},query:{}})
声明式导航
点击链接实现导航的方式,叫做声明式导航
编程式导航
调用aip实现导航的方式,叫做编程式导航
push
this.$router.push(‘hash地址):增加历史记录
replace
this.$router.replace('hash地址'):不增加历史记录
go
this.$router.go(数值n):在历史记录上移动
this.$router.back();后退一个历史记录
this.$router.forward():前进一个历史记录
导航守卫
全局前置守卫
每次发生路由导航跳转时都会触发全局前置守卫,因此可以在全局前置守卫中进行访问权限控制。
在src源代码目录下,router/index.js
// 导包
import Vue from 'vue'
import VueRouter from 'vue-router'
// 导入组件
import Home from '@/components/Home.vue'
// 在Vue上安装VueRouter插件
Vue.use(VueRouter)
// 创建实例配置路由规则并默认导出
const router = new VueRouter({
routes:[
{path:'/home',name:'home',component:Home}
]
})
// to:将要访问的 路由信息对象 from:将要离开的路由信息对象 next:放行函数
在当前页面
router.beforeEach((to,from,next)=>{
//to.path:将要访问的路由字符串(请求路径) this.$router.path
// next():直接放行
// next('/login'):跳转到登录页面
// next(false):不允许跳转,停留在当前页面
}) // 路由导航跳转回调
export default router
this.$route:路由信息对象
this.$route.fullPath:#后的全部字符串
this.$route:路径相关信息
this.$route.params:动态参数对象
this.$route.path:路径参数
this.$route.query:请求参数
在组件里面可以通过 this.$route.params.id获取路由规则里面的值
Vuex
安装
npm i vuex -S
导入挂载创建
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
// state全局共享数据
state: {
count:0
},
getters: {
},
// 定义(同步)函数参数1接收state对象
mutations: {
},
//
actions: {
},
modules: {
}
})
属性
state
state全局共享数据
定义
state: {
count:0
},
访问state(不允许直接修改)
-
通过this.$store.state.count访问
-
映射成计算属性
import {mapState} from 'vuex' export default { computed:{ ...mapState(['count']) // 也可以写函数式:...mapState({count:(state)=>state.count}) } }
getters
在getters定义函数,函数参数1接收state对象
用于对state里的数据进行加工不修改,类似与Vue计算属性
定义
getters: {
getCount(state){
return 'the count is' + state.count
}
},
调用getters里函数
-
通过this.$store.getters.getCount调用
-
映射成计算属性
import {mapGetters} from 'vuex' export default { computed:{ ...mapGetters(['getCount']) } }
mutations
在mutations定义同步函数,函数参数1接收state对象
最好只执行同步代码,devtools调试工具需要捕捉到前一状态和后一状态的快照,如果执行了异步操作devtools调试工具对于异步的操作无法记录(虽然异步也不会报错)
定义
mutations: {
add(state,n){ // 定义函数 参数1:state
state.count += n
}
},
调用mutations里函数(不要有异步代码)
-
通过this.$router.commit('add',3)
-
映射成方法
import {mapMutations} from 'vuex' export default { methods:{ ...mapMutations(['add']) } }
actions
在mutations可以定义异步函数,函数参数1接收一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit
提交一个 mutation
定义
actions: {
asyncAdd(context,n){ // 定义函数 参数1:state
setTimeout(()=>{
context.commit('add',n)
},1000)
}
},
调用actions里函数
-
通过this.$router.dispatch('asyncAdd',3)
-
映射成方法
import {mapActions} from 'vuex' export default { methods:{ ...mapActions(['asyncAdd']) } }
modules
Vuex 允许我们将 store 分割成模块(module) 。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块
挂载实例
import Vue from 'vue'
import App from './App.vue'
import store from './store'
new Vue({
store,
render: h => h(App)
}).$mount('#app')
axios
安装
npm i axios -S
get
import axios from "axios"
axios.get(url,{请求参数})
post
import axios from "axios"
axios.get(url,{请求参数})
配置挂载到Vue原型
main.js
import axios from "axios"
axios.defaults.baseURL = "http://localhost:9090"
// axios.defaults.baseURL = location.origin 配置到服务器域名
Vue.prototype.$http = axios
脚手架
全局安装
npm install -g @vue/cli
升级
npm install -g @vue/cli
创建
vue create hello-world
启动
npm run serve
编译
npm run build
踩坑日记
img动态src
<img :src="require(`../assets/${titles.cover}`)" alt="" srcset="" />
<!-- 动态拼接rsc时,需要通过require导入模块的形式导入,不能直接修改rsc字符串,因为图片也会被webpack打包修改文件名 -->