vue初学随笔
Vue基础
Vue基本概念
Vue是什么
Vue是一个渐进式的JavaScript框架,它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。
- 渐进式:各个特性可以根据项目需要逐渐引入和应用,如Vue Router、Vuex
- 框架:高度封装,拥有自己的规则和元素
- 声明式:Vue基于标准HTML拓展了一套模板语法,使得我们可以声明式地描述最终输出的HTML和JavaScript状态之间的关系
- 组件化:将应用划分为多个独立、可复用的模块
- 响应性:Vue 会自动跟踪JavaScript状态并在其发生变化时响应式地更新DOM
@vue/cli脚手架
@vue/cli脚手架是什么
@vue/cli是Vue官方提供的一个全局模块包,用于创建脚手架项目,它是一个自动化构建项目的工具,帮助开发者快速搭建Vue.js项目的开发环境,其具有开箱即用、无需配置webpack(如babel支持、css和less支持、开发服务器支持)等有点
@vue/cli生成的文件夹目录结构及其作用
-
node_modules:项目依赖的三方包
-
public:静态资源文件
- favicon.io:浏览器小图标
- index.html:单页面的HTML文件
-
src:业务文件夹
- assets:静态资源
- components:组件目录
- App.vue:应用根组件
- main.js:入口js文件
-
.gitignore:git提交忽略配置
-
babel.config.js:babel配置
-
package.js:项目依赖包列表
-
vue.config.js:webpack配置
-
yarn.lock:项目包版本锁定和缓存地址
index.html、main.js 、App.vue的引用关系
引用关系:index.html => main.js => App.vue
Vue指令基础
插值表达式
插值表达式 {{表达式}}
,也叫声明式渲染、文本插值。变量写在data
里,写在data的变量会被vue自动绑定this到当前组件
bind绑定
基础语法
bind绑定可以给标签绑定属性,其写法为:v-bind:属性名="vue变量名"
,简写为::属性名="变量名"
动态class
语法::class="{ 类名: 布尔变量 }
<template><div :class="{ redStr: bool }">动态class,值为true时可以作为类名生效{{ bool }}</div>
</template><script>
export default {data() {return {bool: false,}},
}
</script><style scoped>
.redStr {color: red;
}
</style>
动态style
语法::style="css属性名:值"
<template><div :style="{ color: colorStr }">动态style,对style的值进行赋值</div>
</template><script>
export default {data() {return {colorStr: 'red',}},
}
</script>
v-on事件绑定
vue通过v-on
给标签绑定事件,其写法为v-on:事件名="短代码/函数"
,简写为:@事件名=短代码/函数
,绑定的函数写在methods
里或使用箭头函数
获取事件对象
- 无实参:直接在事件处理函数中通过形参接收
- 有实参:通过
$event
实参指代事件对象传给事件处理函数
<template><div><!-- 阻止默认事件-无实参 --><a:href="url"@click="vuePreventDefault">baidu</a><br /><!-- 阻止默认事件-有实参 --><a:href="url"@click="vuePreventDefault2(1, $event)">baidu2</a></div>
</template><script>
export default {data() {return {url: 'https:\\www.baidu.com',}},methods: {// 阻止默认事件-无实参vuePreventDefault(e) {e.preventDefault()},// 阻止默认事件-有实参vuePreventDefault2(num, e) {console.log(num)e.preventDefault()},},
}
</script>
v-on修饰符
给事件添加常用的功能,语法:@事件名.修饰符=函数名
,常用修饰符有:
.stop
阻止冒泡.prevent
阻止默认行为.once
程序运行期间只触发一次事件处理函数- 按键修饰符:
@keyup.enter
监测回车键@keyup.esc
监测返回键- 更多修饰符参考开发文档events介绍
<template><!-- 事件修饰符 --><a:href="url"@click.prevent="vuePreventTest">baidu</a>
</template><script>
export default {data() {return {url: 'https:\\www.baidu.com',}},methods: {vuePreventTest() {console.log('超链接跳转失效了')},},
}
</script>
v-model双向绑定
通过v-model
可以实现数据变量与表单数据的双向绑定,其内部实现也是通过v-bind
数据绑定和v-on
事件绑定实现的,相对于一个语法糖
<template><inputtype="text"v-model="vueModel"@change="print"/>
</template><script>
export default {data() {return {vueModel: '哈哈哈',}},methods: {print() {console.log(this.vueModel)},},
}
</script>
复选框的情况
遇到复选款,若v-model
的值为非数组类型,则关联的是复选框的checked
属性,为数组时关联的才是value
值。
<template><div><inputtype="checkbox"v-model="hobby"value="吃饭"/>吃饭<inputtype="checkbox"v-model="hobby"value="睡觉"/>睡觉<inputtype="checkbox"v-model="hobby"value="打豆豆"/>打豆豆</div>
</template><script>
export default {data() {return {hobby: [], //必须是数组,否则关联的是选中状态true/false}},
}
</script>
v-model修饰符
给v-model
添加常用功能,如类型转换、去除空白等
.number
以parseFloat转换成数字类型.trim
去除收费空白字符.lazy
在change时(失去焦点)触发而非input时触发
v-text和v-html
通过变量控制innerText
和innerHtml
<template><div><!-- 按innerText --><p v-text="str"></p><!-- 按innerHtml --><p v-html="str"></p></div>
</template><script>
export default {data() {return {str: '<span>我是一个span标签<span/>',}},
}
</script>
v-if和v-show
通过变量控制标签的显示和隐藏,区别:v-show
采用display:none
的方式控制隐藏和显示,适合频繁切换,而v-if
直接将元素从DOM树添加和移除的方式控制显示和隐藏,在频繁切换时效率低下。v-if
可以搭配v-else-if
和v-else
使用
<template><div><!-- v-show --><div v-show="age >= 18">Enter</div><!-- v-if --><div v-if="age >= 60">Ban</div><div v-else-if="age >= 18">Enter</div><div v-else>Ban</div></div>
</template><script>
export default {data() {return {age: 25,}},
}
</script>
v-for
基本用法
v-for
可以实现列表渲染,所在标签结构会按照数据数量循环生成,语法为v-for="(值变量,索引变量) in 目录结构" :key="唯一值"
<template><div><!-- v-for列表渲染 --><ul><liv-for="(item, index) in arr":key="item">{{ `item:${item}; index${index}` }}</li></ul></div>
</template><script>
export default {data() {return {arr: [1, 2, 3, 4, 5, 6, 7],}},
}
</script>
数组更新检测
数组便跟方法改变数组,导致v-for
更新,页面刷新,非数组便跟方法返回新数组,可以使用覆盖数组或this.$set()
更新
<template><div><!-- v-for列表渲染 --><ul><liv-for="(item, index) in arr":key="item">{{ `item:${item}; index${index}` }}</li></ul><button @click="arr.push(1)">push</button></div>
</template><script>
export default {data() {return {arr: [1, 2, 3, 4, 5, 6, 7],}},
}
</script>
v-for就地更新
虚拟DOM本质上时JS和DOM之间的应该映射,在形态上表现为应该能够描述DOM结构及其属性信息的JS对象,帮助我们在更爽更高效的研发模式下保证还有良好的性能。
当数据发生改变后,会先在内存中创建新的虚拟DOM,并与旧的虚拟DOM按一定规则进行比较,然后决定是否复用真实DOM。
传统算法对树形结构的比较通过递归对树节点进行一一对比,时间复杂度为O(n³),效率过于低下,而diff算法时间复杂度为O(n),其关键是:
- 分层对比:因为DOM 节点之间的跨层级操作并不多,同层级操作才是主流,Diff 过程直接放弃了跨层级的节点比较,它只针对相同层级的节点作对比,只需要从上到下的一次遍历,就可以完成对整棵树的对比,以此降低复杂度量级。
- 类型一致的节点才有进行Diff的必要性,只有同类型的组件,才有进一步对比的必要性
- 通过key属性的设置尽可能复用同一层级内的节点,通过识别key可能知道只是顺序发生了变化,就可以只进行插入或删除操作,大量降低成本
<template><div><!-- v-for列表渲染 --><ul><liv-for="item in arr":key="item">{{ `item:${item}` }}</li></ul><!-- 更新 --><button @click="arr.splice(2, 0, arr.length + 1)">insert</button></div>
</template><script>
export default {data() {return {arr: [1, 2, 3, 4, 5, 6, 7],}},
}
</script>
这里可以看到控制台中只有插入的元素闪动了,即只更新了插入部分
过滤器filter
过滤器是用来格式化数据的,其就是一个函数,传入值后返回处理过的值,只能用在插值表达式和v-bind动态属性里
全局过滤器
定义过滤器
// main.js
import Vue from 'vue'
import App from './App.vue'Vue.config.productionTip = false// 定义全局过滤器
Vue.filter('reverse', val => val.split('').reverse().join(''))new Vue({render: h => h(App),
}).$mount('#app')
使用过滤器
<!-- xx.vue -->
<template><div><div>{{ '过滤器的使用' + msg }}</div><!-- 使用翻转过滤器 --><div>{{ msg | reverse }}</div></div>
</template><script>
export default {data() {return {msg: 'Hello World',}},
}
</script>
局部过滤器
<!-- xx.vue -->
<template><div><div>{{ '过滤器的使用' + msg }}</div><!-- 使用翻转过滤器 --><div>{{ msg | reverseLocal }}</div></div>
</template><script>
export default {data() {return {msg: 'Hello World',}},// 定义局部过滤器filters: {reverseLocal: val => val.split('').reverse().join(''),},
}
</script>
过滤器可以同时使用多个,增加|
隔开即可,也可传递参数,使用方法同函数
<!-- xx.vue -->
<template><div><div>{{ '过滤器的使用' + msg }}</div><!-- 使用多个过滤器,并带有参数 --><div>{{ msg | toUp | reverseLocal('|') }}</div></div>
</template><script>
export default {data() {return {msg: 'Hello World',}},// 定义多个过滤器,并带有参数filters: {reverseLocal: (val, s) => val.split('').reverse().join(s),toUp: val => val.toUpperCase(),},
}
</script>
计算属性computed
基本用法
一个变量的值依赖另外一些变量计算而来就是计算属性,计算属性函数内的变量改变,会重新返回新的计算结果并渲染页面
<!-- xx.vue -->
<template><div><div>{{ '计算属性a+b:' + a + '+' + b }}</div><!-- 使用计算属性 -->{{ addAB }}</div>
</template><script>
export default {data() {return {a: 1,b: 2,}},// 定义计算属性computed: {addAB() {return this.a + this.b},},
}
</script>
特性
计算属性带有缓存机制,计算数学定义函数执行后会把return
值缓存起来,依赖项不点,多次调用也是从缓存中取值,当依赖项改变时才会自动重新执行并返回新的值
完整写法
在将计算属性直接通过v-model
关联到input
输入后发现,会报错,原因是无法直接通过v-model
双向绑定修改计算属性的值,这个时候时需要用到setter
的完整写法
<script>
export default {computed: {computedName: {set(val) {// 设置值时触发的代码},get() {// 获取值时触发的代码},},},
}
</script>
侦听器watch
基本语法
侦听器可以侦听data/computed属性值的改变
<script>
export default {data() {return {// 被侦听的变量name: '',}},// 侦听器watch: {name(oldValue, newValue) {console.log(newValue, oldValue)},},
}
</script>
完整写法
基本语法通过函数实现,但无法对复杂类型进行侦听,也无法设置执行时机,这个时候就要用到完整写法
<!-- xx.vue -->
<template><div>姓:<inputtype="text"v-model="name.lastName"/>名:<inputtype="text"v-model="name.firstName"/></div>
</template><script>
export default {data() {return {// 被侦听的变量name: {lastName: '',firstName: '',},}},// 侦听器watch: {name: {immediate: true, // 页面一打开就执行一次侦听deep: true, // 深度侦听handler(newValue, oldValue) {console.log(newValue)console.log(oldValue)},},},
}
</script>
Vue组件
组件是可复用的Vue实例,封装了标签、样式和JS代码,把页面上可复用的部分封装为组件,可以便捷的开发和维护项目。组件使用如下:
- 创建组件
xxx.vue
,封装标签、样式、js代码 - 注册组件:
- 全局注册:在
main.js
中Vue.component('组件名', 组件对象)
- 局部注册:在某
xx.vue
文件中,export default{components: {"组件名": 组件对象 }}
- 全局注册:在
- 引入并使用组件
组件样式scoped作用及其原理
scoped
可以让CSS样式只在当前组件生效,其作用原理是为组件添加机的哈希值data-v-hash
值属性,在获取标签时也会添加[data-v-hash]
的属性选择器,从而保证CSS类名只针对当前的组件生效
组件之间的通信
父传子——props
子组件内定义props接收数据,父组件传递props到子组件实现
儿子:
<!-- MyProduct.vue -->
<template><div class="my-product"><!-- 使用变量 --><h3>标题: {{ title }}</h3><p>价格: {{ price }}元</p><p>{{ intro }}</p></div>
</template><script>
export default {// 定义变量准备接收props: ['title', 'price', 'intro'],
}
</script>
父亲:
<!-- app.vue -->
<template><div id="app"><!-- 3.使用子组件 --><Productv-for="(product, index) in productList":key="product.id":title="product.name":price="product.price":intro="product.intro":index="index"/></div>
</template><script>
// 1.引入子组件
import Product from './components/MyProduct'export default {data() {return {productList: [{id: 1,name: '钵钵鸡',price: 1,intro: '一元一串的钵钵鸡',},{id: 2,name: '肯德基',price: 50,intro: 'Crazy星期四,V我50',},{id: 3,name: '椰子鸡',price: 100,intro: '深圳特产海南椰子鸡',},],}},components: {// 2.注册子组件Product,},
}
</script>
**单向数据流:**指的是数据从父组件流向子组件的过程,这种单向数据流能保证数据易于追踪、减少组件之间的耦合度、提高性能。父传子的props
是只读的,不允许修改的。(注意Vue可以不是单向数据流,如eventBus,兄弟之间通信通过中介实现,所以Vue中的单向数据流特指的是直接的通信)
子传父$emit
父组件定义自定义事件,子组件提高$emit
主动触发事件实现
父亲:
<!-- app.vue -->
<template><div id="app"><!-- 父组件中给子组件绑定自定义事件——砍价函数 --><Productv-for="(product, index) in productList":key="product.id":title="product.name":price="product.price":intro="product.intro":index="index"@subPrice="subPrice"/></div>
</template><script>
import Product from './components/MyProduct_sub'export default {data() {return {productList: [{id: 1,name: '钵钵鸡',price: 1,intro: '一元一串的钵钵鸡',},{id: 2,name: '肯德基',price: 50,intro: 'Crazy星期四,V我50',},{id: 3,name: '椰子鸡',price: 100,intro: '深圳特产海南椰子鸡',},],}},methods: {// 定义砍价函数subPrice(index) {this.productList[index].price *= 0.9},},components: {Product,},
}
</script>
儿子:
<!-- MyProduct.vue -->
<template><div class="my-product"><h3>标题: {{ title }}</h3><p>价格: {{ price }}元</p><p>{{ intro }}</p><!-- 子组件触发父组件绑定的自定义事件,父组件绑定的函数执行 --><button @click="subFn">PDD大宝刀,一刀999</button></div>
</template><script>
export default {props: ['index', 'title', 'price', 'intro'],methods: {subFn() {this.$emit('subPrice', this.index)},},
}
</script>
跨组件通信eventBus
父组件管理数据
兄弟组件之间的通信实际上通过上面的学习已经可以实现了,其实很简单,把全部数据都丢给父组件管理,通过父子之间的通信转化为兄弟之间的通信,但是这种方法依赖于父组件的介入,可能会使得组件之间的耦合度增加。、
evebntBus
当需要在两个兄弟组件之间进行通信时,可以创建一个eventBus
实例,并在两个组件中都通过$on
来监听事件,通过$emit
来触发事件。这样,当一个组件触发事件时,另一个组件就可以接收到这个事件并进行相应的处理。
首先:先要创建一个空白的Vue对象并导出:src/EventBus/index.js
import Vue from 'vue'
export default new Vue()
接收方要引入空白Vue对象eventBus
并通过$on
监听事件
<!-- List.vue -->
<template><ul class="my-product"><liv-for="(item, index) in arr":key="index"><span>{{ item.name }}</span><span>{{ item.price }}</span></li></ul>
</template><script>
// 引入eventBus
import eventBus from '../eventBus'export default {props: ['arr'],// 组件创建完毕时,监听send事件created() {eventBus.$on('send', index => {this.arr[index].price *=0.5})}
}
</script>
发送方也要引入eventBus
,然后通过eventBus触发事件
<!-- MyProduct.vue -->
<template><div class="my-product"><h3>标题: {{ title }}</h3><p>价格: {{ price }}元</p><p>{{ intro }}</p><button @click="subFn2">PDD大宝刀,一刀打骨折</button></div>
</template><script>
// 引入eventBus
import eventBus from '../eventBus'export default {props: ['index', 'title', 'price', 'intro'],methods: {subFn() {this.$emit('subPrice', this.index)},subFn2() {eventBus.$emit('send', this.index)}},
}
</script>
Vue组件的生命周期
Vue的生命周期指的是Vue组件从创建到销毁的过程,Vue框架内置了钩子函数,随着组件生命周期阶段自动执行。Vue中生命周期共4个阶段,8个方法
生命周期 | 钩子函数 | 钩子函数 |
---|---|---|
初始化 | beforeCreate | created |
挂载 | beforeMount | mounted |
更新 | beforeUpdate | updated |
销毁 | beforeDestory | destoryed |
生命周期如下图:
初始化阶段
- new Vue():Vue组件实例化
- Init Events & Lifecycle:初始化事件和生命周期函数
- beforeCreate:生命周期钩子函数被执行,此时是访问不到data和method的
- Init injections & reactivity:Vue内部添加data和methods等
- created:生命周期钩子函数被执行,实例创建
挂载阶段
- 编译模板阶段:开始分析Has "el"option:检查是否有el选项(如
#App
):- 没有:调用$mount方法
- 有:继续检查有无template选项
- 有:编译template返回render函数
- 无:找到并编译
el
选项对应的标签作为要渲染的模板template
- beforeMount:生命周期钩子函数被执行,此时虚拟DOM还没有被挂载成为真实DOM
- Create vm.$el and replace “el” with it:把虚拟DOM挂载成为真实的DOM
- mounted:生命周期钩子函数被执行,真实DOM挂载完毕,此时可以访问到真实DOM
更新阶段
- 修改数据进入更新阶段
- beforeUpdate:生命周期钩子函数被执行,此时DOM还没被更新(这里不能访问DOM,因为Vue的响应式是异步的,可能还是取到更新后的DOM)
- Virtual DOM re-render and patch:虚拟DOM重新渲染,对真实DOM进行打补丁
- updated:生命周期钩子函数被执行,此时虚拟DOM已更新
销毁阶段
此时要移除一些组件占用的全局资源,如定时器、计时器、全局事件等
- vm.$destory()被调用,比如组件被移除(view-if)
- beforeDestroy:生命周期钩子函数被执行
- 拆卸数据监视器、子组件、事件侦听器
- destroyed:生命周期钩子函数被执行
ref 和nextTick
ref
通过ref获取元素:
<template><!-- 设置ref --><divid="h"ref="myRef">ref</div>
</template><script>
export default {mounted() {// 获取DOM的两种方法console.log(document.getElementById('h'))console.log(this.$refs.ref)},// 后面通过ref获取组件可以methods: {sonFn() {console.log('son的方法执行了')},},
}
</script>
通过ref获取组件:
<template><div id="app">// 给组件添加ref<Ref ref="myComRef" /></div>
</template><script>
import Ref from './components/Ref.vue'
export default {components: {Ref,},mounted() {// 获取组件console.log(this.$refs.myComRef)// 获取的组件可以调用组件内的方法了this.$refs.myComRef.sonFn()},
}
</script>
$nextTick
DOM更新后挨个触发$nextTick
中的函数体执行,而直接调用this.$nextTrick()
返回的是一个Promise对象
<template><div id="app"><button@click="btnFn"ref="btnRef">{{ count }}</button></div>
</template><script>
export default {data() {return {count: 0,}},methods: {btnFn() {this.count++console.log(this.$refs.btnRef.innerHTML) // 这里点击按钮还是0this.$nextTick(() => {console.log(this.$refs.btnRef.innerHTML) // 这里可以拿到数字1了})},},
}
</script>
动态组件和组件缓存
<component :is="componentName">
和<keep-alive>
component+is可以实现组件的动态切换,会根据is后面的字符串匹配组件名展示组件,配合keep-alive标签包裹的组件可以缓存到内存中,不会被立即销毁,实现动态组件切换
<template><div id="app"><div>动态组件</div><!-- keep-alive标签包裹实现组件缓存 --> <keep-alive><!-- component+is 实现动态组件 --> <component :is="comName"></component></keep-alive><button @click="comName = 'Life'">切换组件Life</button><button @click="comName = 'Ref'">切换组件Ref</button></div>
</template><script>
import Life from './components/Life.vue'
import Ref from './components/Ref.vue'
export default {data() {return {comName: 'Life',}},components: {Life,Ref,},
}
</script>
activated和deactivated钩子函数
activated在组件激活时触发,deactivated在组件失去激活状态时触发,注意组件的created
和mounted
钩子函数只会执行一次,而当组件再次被激活时,会触发activated
钩子函数,而不是再次执行created
或mounted
。
<script>
export default {data() {return {msg: 'hello world',arr: [1, 1, 1, 1, 1],}},activated() {console.log('被激活了')},deactivated() {console.log('失活了')},
}
</script>
组件插槽
基本语法
通过slot标签,让组件内可以接受不同的标签结构显示,组件插入什么标签就显示什么标签
<template><div id="container"><div id="app"><h3>案例:折叠面板</h3><!-- 组件插入内容 --> <PannelSlot><p>寒雨连江夜入吴,</p><p>平明送客楚山孤。</p><p>洛阳亲友如相问,</p><p>一片冰心在玉壶。</p></PannelSlot></div></div>
</template>
<template><div><div class="title"><h4>芙蓉楼送辛渐</h4><spanclass="btn"@click="isShow = !isShow">{{ isShow ? '收起' : '展开' }}</span></div><divclass="container"v-show="isShow"><!-- 插槽 --><slot></slot></div></div>
</template>
设置默认内容
不给slot标签放置内容,slot标签内的内容作为默认内容显示
<!-- 插槽 --><slot><p>寒雨连江夜入吴,</p><p>平明送客楚山孤。</p><p>洛阳亲友如相问,</p><p>一片冰心在玉壶。</p></slot>
具名插槽
一个组件内有多出需要外部传入标签的地方,使用多个插槽时就需要用到具名插槽,通过name区分slot
名字,并通过template配合v-slot:name
区分插入的地方
<template><div id="container"><div id="app"><h3>案例:折叠面板</h3><!-- 具名插槽 --><PannelSlot><template v-slot:title><h4>芙蓉楼送辛渐</h4></template><template v-slot:content><p>寒雨连江夜入吴,</p><p>平明送客楚山孤。</p><p>洛阳亲友如相问,</p><p>一片冰心在玉壶。</p></template></PannelSlot></div></div>
</template>
<template><div><div class="title"><!-- 具名插槽 --><slot name="title"></slot><spanclass="btn"@click="isShow = !isShow">{{ isShow ? '收起' : '展开' }}</span></div><divclass="container"v-show="isShow"><!-- 具名插槽 --><slot name="content"> </slot></div></div>
</template>
作用域插槽
使用插槽时需要使用到子组件内的变量就要用到作用域插槽。在子组件中的slot
标签上绑定属性和子组件内的之,然后再使用组件时传入自定义标签,通过template
标签和v-slot="自定义变量名"
获取变量.
<template><div><!-- 作用域插槽:下拉内容 --><slotname="scopedSlot":row="defaultObj">{{ defaultObj.one }}</slot></div>
</template><script>
export default {data() {return {isShow: false,defaultObj: {one: '1',two: 2,},}},
}
</script>
<template><div id="container"></PannelSlot><!-- 使用作用域插槽 --><!-- 这里我们任意取名scope,它会绑定slot上所有属性和值 --><template v-slot:scopedSlot="scope"> {{ scope.row.two }}</template></PannelSlot></div>
</template>
自定义指令
自定义指令可以给组件拓展额外功能,如自动获取焦点
全局注册
Vue.directive('gfocus', {inserted(el) { // inserted:标签被插入网页时才触发,还有update// 可以对el标签扩展额外功能el.focus() // 触发标签事件方法}
})
局部注册
<script>
export default {directives: { // 自定义组件focus: {inserted(el) {// 对el进行操作el.focus()}}}
}
</script>
使用自定义指令
<template><input type="text" v-focus>
</template>
自定义指令传值
Vue.directive('color', {inserted(el, bindingColor) { // inserted:标签被插入网页时才触发// 可以对el标签扩展额外功能el.style.color = bindingColor.value // 触发标签事件方法}
})
自定义指令触发方法
inserted:标签被插入网页时才触发
update:自定义指令所在标签刷新时执行
路由Router
基本使用
vue-router基本使用
- 下载vue_router模块到当前工程
- 在main.js中引入VueRouter函数
- 添加到Vue.use()身上:注册全局RouterLink和RouterView组件
- 创建路由规则数组:路径和组件名的对应关系
- 用规则生成路由对象
- 把路由对象注入到new Vue实例中
- 用router-view作为挂载点切换不同路由页面
// main.js
import Vue from 'vue'
import App from './App.vue'
import Find from './views/Find/Find.vue'
import Mine from './views/Mine/Mine.vue'
import Friends from './views/Friends/Friends.vue'// 在main.js中引入VueRouter函数
import VueRouter from 'vue-router'// 2. 注册全局组件
Vue.use(VueRouter)// 3. 定义规则数组
const routes = [{path: '/find',component: Find,},{path: '/mine',component: Mine,},{path: '/friends',component: Friends,},
]
// 4. 生成路由对象
const router = new VueRouter({routes: routes, //routes是固定key,传入规则数组,同名可以简写直接写routes
})Vue.config.productionTip = false// 5. 将路由对象注入到vue实例中,this可以访问$route和$router
new Vue({router,render: h => h(App),
}).$mount('#app')
<!-- App.vue -->
<template><div><a href="#/find">发现音乐</a><br /><a href="#/mine">我的音乐</a><br /><a href="#/friends">我的朋友</a><!-- 6.设置挂载点,当url的hash值路径切换,显示规则里对应的组件到这里 --><router-view></router-view></div>
</template>
声明式导航
router-link基本使用
vue-router提供了一个全局组件router-link来代替a标签,其实质上最终会渲染成a链接,其to
属性等价于href
,但to
使用时无需用到#
(自动添加),它还通过自带类名router-link-active
、router-link-exact-active
提供了声明式导航高亮的功能。router-link-active
会在当前路由匹配到的路由及其子路由上添加,而 router-link-exact-active
仅在当前路由完全匹配时添加
<!-- App.vue -->
<template><div><!-- 这里改成了router-link和to --><router-link to="/find">发现音乐</router-link><br /><router-link to="/mine">我的音乐</router-link><br /><router-link to="/friends">我的朋友</router-link><router-view></router-view></div>
</template>
router-link跳转传参
- 通过
/path?参数名=值
,通过$route.query.参数名
获取值
<router-link to="/find?name=哈哈">发现音乐</router-link>
<template><div><div>发现音乐</div><div>发现传入值:{{ $route.query.name }}</div></div>
</template>
- 通过路由设置
path/:参数名
,再经path/值
传递参数,在组件中使用$route.params.参数名
接收参数
const routes = [{path: '/friends/:name', // 通过冒号接收具体值component: Friends,},
]
<router-link to="/friends/小vue">我的朋友</router-link>
<div>发现传入值:{{ $route.params.name }}</div>
路由重定向
通过redirect
实现路由重定向
const routes = [{path: '/',redirect: '/find',},
]
404
const routes = [// 404一定要在规则数组的最后{path: '*',component: NotFound,},
]
hash路由和history路由切换
hash路由是带#
的,如http://localhost:3000/#/friends
,切换为history模式为http://localhost:3000/friends
,但这在上线时需要服务器端支持,否则寻找到的是文件夹
const router = new VueRouter({routes,mode:"history"
})
编程式导航基本使用
编程式导航即通过js实现路由的跳转,以下path
、name
二者选一即可。这里vue-router要么安装3.0以下版本,要么再传递两个回调函数,作为成功和失败的回调,否则重复push到同一个路由报错Avoided redundant navigation to current location
,因为3.0以上版本返回的是Promise,需要增加两个回调
this.$router.push({// path: '路由路径',name: '路由名' // 使用路由名字在规则数组中需要添加name属性
})
query和params的区别:
query
:通过URL的查询字符串传递参数,它会显示在URL中,且不会影响路由的匹配。params
:通过name
的路由参数传递,它不会显示在URL中,且必须与name
的路由规则匹配。
编程式导航传参
this.$router.push({// path: '路由路径',name: '路由名',query: {'参数'},params: { // 使用params只能用name'参数'}
})
二级路由
二级路由通过配置规则数组路由的``children`实现
const routes = [{path: '/find',name: 'find',component: Find,// 配置children children: [{path: 'second', // 这里不需要/component: Second,},],},
]
<template><div><div>发现音乐</div><!-- 这里还是要加上/find/ --><router-link to="/find/second">链接到Second</router-link><!-- 用来展示组件 --><router-view></router-view></div>
</template>
<script>
export default {}
</script>
路由守卫
路由守卫可以让路由跳转前先触发一个函数,进行守护,主要用于路由权限判断
router.beforeEach((to, from, next) => {// to: Object 要跳转到的路由对象信息// from: Object 从哪里跳转的路由对象信息// next: Function next()路由正常切换 next(false)原地停留 next("路径")强制修改到另一个路由上 不调用next也停留在原地
})
riends`,但这在上线时需要服务器端支持,否则寻找到的是文件夹
const router = new VueRouter({routes,mode:"history"
})
编程式导航基本使用
编程式导航即通过js实现路由的跳转,以下path
、name
二者选一即可。这里vue-router要么安装3.0以下版本,要么再传递两个回调函数,作为成功和失败的回调,否则重复push到同一个路由报错Avoided redundant navigation to current location
,因为3.0以上版本返回的是Promise,需要增加两个回调
this.$router.push({// path: '路由路径',name: '路由名' // 使用路由名字在规则数组中需要添加name属性
})
query和params的区别:
query
:通过URL的查询字符串传递参数,它会显示在URL中,且不会影响路由的匹配。params
:通过name
的路由参数传递,它不会显示在URL中,且必须与name
的路由规则匹配。
编程式导航传参
this.$router.push({// path: '路由路径',name: '路由名',query: {'参数'},params: { // 使用params只能用name'参数'}
})
二级路由
二级路由通过配置规则数组路由的``children`实现
const routes = [{path: '/find',name: 'find',component: Find,// 配置children children: [{path: 'second', // 这里不需要/component: Second,},],},
]
<template><div><div>发现音乐</div><!-- 这里还是要加上/find/ --><router-link to="/find/second">链接到Second</router-link><!-- 用来展示组件 --><router-view></router-view></div>
</template>
<script>
export default {}
</script>
路由守卫
路由守卫可以让路由跳转前先触发一个函数,进行守护,主要用于路由权限判断
router.beforeEach((to, from, next) => {// to: Object 要跳转到的路由对象信息// from: Object 从哪里跳转的路由对象信息// next: Function next()路由正常切换 next(false)原地停留 next("路径")强制修改到另一个路由上 不调用next也停留在原地
})
相关文章:

vue初学随笔
Vue基础 Vue基本概念 Vue是什么 Vue是一个渐进式的JavaScript框架,它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。 渐进式:各个特性可以根据项目需要逐渐引入和…...

IDEA Dependency Analyzer 分析 maven 项目包的依赖
一、场景分析 javax.validation 是我们 SpringMVC 常用的数据校验框架。但是 javax.validation 是一个规范(Java Bean Validation,简称 JSR 380),它并没有具体的实现,它的常用实现,是hibernate-validator。…...

微信小程序 - 最新详细安装使用 Vant weapp UI 框架环境搭建详细教程
前言 自从 2024 年开始,小程序做了很多改变和升级, 导致网上很多搭建教程文章的教程失效了,本文来做最新的教程。 第一步 为了更贴合新手,我这里创建了一个纯净无任何业务代码的小程序项目。...

【C语言】手把手带你拿捏指针(完)(指针笔试、面试题解析)
文章目录 一、sizeof和strlen的对⽐1.sizeof2.strlen3.sizeof与strlen对比 二、数组和指针笔试解析1.一维数组2.字符、字符串数组和字符指针代码1代码2代码3代码4代码5代码6 3.二维数组4.总结 三、指针运算笔试题解析代码1代码2代码3代码4代码5代码6 一、sizeof和strlen的对⽐ …...
Vue中input框自动聚焦
在Vue中input自动聚焦的思路: 给需要聚焦的input设置ref <el-inputv-model"loginForm.username"ref"userNameInput"name"username"type"text"auto-complete"on"placeholder"username"keyup.enter.…...

基于Node.js+Express+MySQL+VUE实现的计算机毕业设计旅游推荐网站
猜你喜欢评论 登录注册搜索 推荐定制景点/springboot/javaWEB/J2EE/MYSQL数据库/vue前后分离小程序 功能图如下所示: 一、设计目标 本次计算机毕业设计项目的主要目标是设计和开发一款功能完善、用户友好的旅游推荐网站。该网站旨在为广大旅游爱好者提供一个便捷、…...

已存在的Python项目使用依赖管理工具UV
1. 文档 uv文档 2. 如何转换 初始化 uv initrequirements.txt转换成pyproject.toml uv add $(cat requirements.txt)删除requirements.txt 如果更新pyproject.toml之后,使用命令 uv sync替换项目环境 如果有库没有加入依赖,自己手动加一下&am…...

JavaWeb美食推荐管理系统
目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 spring-mybatis.xml3.5 spring-mvc.xml3.5 login.jsp 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍:CSDN认证博客专家,CSDN平台Java领域优…...

如何像专家一样修复任何 iPhone 上的“iPhone 已禁用”错误
“我忘记了密码,并且我的 iPhone 在多次输入错误密码后就被禁用了,如何再次访问我的手机?” 作为最安全的数字设备之一,iPhone 必须使用正确的密码解锁。即使您可以使用 Face ID 或 Touch ID 访问您的设备,在充电或重…...
django drf to_representation
使用场景 1.需要对结果的中的某个字段进行进一步的处理; 2.模型类中没有的字段,添加到结果中进行响应; 例子 from django.db import modelsclass TestModel(models.Model):name models.CharField(_("名称"), max_length50, nul…...
2024最新国内镜像源设置(npm、yarn、pnpm)
淘宝镜像源https://registry.npmmirror.com/ 腾讯云镜像源https://mirrors.cloud.tencent.com/npm/ cnpm是一个基于npm的中国镜像源https://r.cnpmjs.org/ # 查询当前使用的镜像源 npm get registry# 设置为淘宝镜像源 npm config set registry https://registry.npmmirror.co…...

Java线程池和原子性
文章目录 前言1 线程池1.1 线程池概述1.1.1 线程池存在的意义1.1.2 Executors默认线程池 1.2 线程状态介绍1.2.1 线程状态源码1.2.2 线程状态含义1.2.3 线程状态转换图 2 原子性2.1 volatile关键字2.2 synchronized解决2.3 原子性2.4 AtomicInteger类2.5 悲观锁和乐观锁 前言 …...
【数据评估与清洗】对数据结构和内容进行清洗
评估数据 结构方面 需要清理:乱数据不需要清理:整洁数据 每列是一个变量每行是一个观察值每个单元格是一个值 内容方面 需要清理:脏数据 丢失数据重复数据不一致数据无效或错误数据 不需要清理:干净数据 # 获取整体信息 df.in…...

机器学习和深度学习的区别
1. 基本概念 1.1 机器学习定义 机器学习是人工智能的一个核心分支,它赋予计算机系统无需明确编程即可学习和改进的能力。通过分析大量数据,机器学习算法能够识别数据中的模式和趋势,从而做出预测或决策。这种方法通常涉及统计模型和优化技术…...

UE虚幻引擎云渲染汽车动画的优势!
在汽车广告和动画制作领域,虚幻引擎(UE)结合云渲染技术正掀起一场技术革命。这项技术以其高性能、成本效益和灵活性,为创作者提供了强大的工具,以实现更加逼真和高效的汽车动画制作。 一、为什么选择UE虚幻引擎制作汽车…...

Teams集成-会议侧边栏应用开发-实时转写
Teams虽然提供了转写的接口,但是不是实时的,即便使用订阅事件也不是实时的,为了达到实时转写的效果,使用recall.ai的转录和assembly_ai的转写实现。 前提:除Teams会议侧边栏应用开发-会议转写-CSDN博客的基本要求外&a…...

归并排序,外排序,计数排序(非比较排序)
归并排序:(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序…...

使用离火插件yoloV8数据标注,模型训练
1. 启动 2.相关配置 2.1 data.yaml path: D:/yolo-tool/yaunshen-yolov8/YOLOv8ys/YOLOv8-CUDA10.2/1/datasets/ceshi001 train: images val: images names: [蔡徐坤,篮球] 2.2 cfg.yaml # Ultralytics YOLOv8, GPL-3.0 license # Default training settings and hyp…...

JavaScript 学习
一、输出 为方便调试可以输出内容,但是用户是看不到的。要在开发者模式中看。 console . log ( "Hello" ); 二、外部文件引用 可以直接在html中写JS <head> <meta charset"utf-8"> <script> console.log("he…...
【算法】分治:归并之 912.排序数组(medium)
系列专栏 双指针 模拟算法 分治思想 目录 1、题目链接 2、题目介绍 3、解法 解决方案选择 解题步骤 4、代码 1、题目链接 912. 排序数组 - 力扣(LeetCode) 2、题目介绍 给你一个整数数组 nums,请你将该数组升序排列。 你必须在 …...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...

51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...