当前位置: 首页 > news >正文

Vue2学习记录

前言

这篇笔记,是根据B站尚硅谷的Vue2网课学习整理的,用来学习的

如果有错误,还请大佬指正

Vue核心

Vue简介

Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架

它基于标准 HTML、CSS 和 JavaScript 构建,

并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面


官网:Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org)

初识Vue

  • Vue进行工作,需要提供 Vue实例 和 模版
  • 通过 new Vue() 创建出Vue实例对象
  • 在Vue实例对象中,需要绑定模板
    <!--准备容器--><div id="test01">Hello {{word}}!!</div><script>//创建Vue实例new Vue({el: '#test01',//指定当前实例为那个模版服务data: {word: 'world'}//提供数据,供指定模版使用})</script>

 MVVM模型

Vue 仿照MVVM来进行设计

分为模型(Model),视图(View)和视图模型(ViewModel)三部分

  • M:模型(Model) -> data中的数据
  • V:视图(View) -> 模版,即 DOM
  • VM:视图模型(ViewModel) -> Vue 实例对象

模版绑定 与 data 写法

模版绑定

方法一:

使用 el 来绑定

语法 : el : ' css选择器 '

        new Vue({el: '#test01',data: {word: 'world'}})

方法二:

语法:实例对象 . $mount ( ' css选择器 ' )

        const vm = new Vue({data: {word: 'world!!!'}})vm.$mount('.test01')

data写法

写法一:对象式

语法:data : { 数据对象 }

            data: {word: 'world!!!'}

写法二:函数式

必须返回一个数据对象

不要写箭头函数

            data: function(){return{word:'world!!!'}}

模版语法

Vue 使用一种基于 HTML 的模板语法,

使我们能够声明式地将其组件实例的数据绑定到呈现的 DOM 上

简单来说:

        将Vue实例中的数据,呈现到 HTML 上

插值语法

可以分析标签体内容(标签包裹内容)

语法:

        {{JS表达式}}

示例:

    <div id="test01">Hello {{word}}<!-- {{}} 中的内容会被替换为Vue实例中的数据--></div><script>new Vue({el:'#test01',data:{word:'world!!!'}})</script>

{{ }} 中的内容会被替换为Vue实例中的数据

指令语法

可以解析标签(标签属性、标签体内容),并可以绑定事件

指令有很多,以 v- 为开头

例:v-bind:  (可简写为 : )

        v-bind : 标签属性 = 'JS表达式'   或   : 标签属性 = 'JS表达式'

    <div id="test02"><a v-bind:href="Prohibited">未满18不要打开</a><!-- "" 中的内容会被替换为Vue实例中的数据--></div><script>new Vue({el: '#test02',data: {Prohibited: 'https://store.steampowered.com/app/2358720/_/'}})</script>

数据绑定

单向数据绑定

语法:

v-bind : 标签属性 = 'JS表达式'   或简写为   : 标签属性 = 'JS表达式'

数据只能从data流向页面

即 修改data中的数据,同时改变页面数据

双向数据绑定

语法:

v-model:value="JS表达式" 或简写为 v-model="JS表达式"

用于有value的标签

数据不仅能从 data 流向页面,还能从页面流向data

即 修改data中的数据,同时改变页面数据 ; 修改页面中的数据,同时改变data数据

数据代理

通过一个对象,代理对另一个对象中的属性的操作(读/写)

Object . defineProperty()

Object . defineProperty()可以为对象添加属性

语法:

Object . defineProperty ( 对象名 , ' 添加属性 ' , {

        get函数 ,

        set函数

})

get函数需要有返回值,作为添加属性的值

当读取所添加属性时,get函数会被调用

当修改所添加属性时,set函数会被调用

        let num = 18let Person = {name: 'zhao',school: 'sn'}Object.defineProperty(Person, 'age', {//读取age时,调用get函数,返回值为age的值get() {return num},//修改age时,调用set函数,修改值作为参数set(value) {num = value//将参数,也就是修改值,传给num}})

使用Object . defineProperty(),实现了Person对num的数据代理,

修改Person的属性值,就可以修改num

Vue中的数据代理

在Vue实例对象中,data的数据存放在Vue._data中

为了更方便地操作data中的数据,Vue通过Object . defineProperty(),

对data中数据进行了数据代理

事件处理 

事件基本使用

使用指令 v-on 来进行事件绑定

语法:v-on : 事件 = " 函数名 "

        简写:@事件 = " 函数名 "

        对应函数需要配置到Vue实例里,methods对象中

    <div><button v-on:click="test01">普通按钮01</button></div><script>const vm=new Vue({el:'div',methods:{test01(){console.log(11111)                    }}})</script>

函数参数

    <div><button v-on:click="test02">普通按钮02</button><button v-on:click="test03(3)">普通按钮03</button><button v-on:click="test04($event,4,44)">普通按钮04</button></div><script>const vm=new Vue({el:'div',methods:{test02(e){console.log(e)console.log(2222)                    },test03(a){console.log(a)console.log(3333)                    },test04(e,a,b){console.log(e,a,b)console.log(4444)}}})</script>

 以上代码为例:

  1. 没有参数时,传入事件对象(test02)
  2. 有参数时,没有事件对象(test03)
  3. 可以用$enevt,来配置事件对象(test04)

注:

  • 不要用箭头函数,因为this将不再指向vm

事件修饰符

用于修饰事件

语法:v-on : 事件 . 事件修饰符 = " 函数名 "

        简写:@事件 . 事件修饰符 = " 函数名 "

事件修饰符作用
prevent阻止事件的默认行为
stop停止事件冒泡
once事件仅触发一次
capture使用事件捕获
selfe.target为当前元素时触发
passive默认行为立即执行,再进行回调函数

示例:

    <div class="out" @click="work">out<div class="in" @click.stop="work"><!--阻止事件冒泡-->in</div></div>

修饰符可以连写

        <div class="in" @click.stop.prevent="work" >

按键修饰符

Vue提供了一些触发键盘事件时使用的按键修饰符

用于在按下某个按键时,触发事件

语法:v-on : 键盘事件 . 按键别名 = " 函数名 "

        简写:@键盘事件 . 按键别名 = " 函数名 "

按键别名为Vue提供,即 按键码的别名

    <!--在按下回车键时触发事件--><input type="text" @keyup.enter="work">

一些常用键盘别名

  • 回车键 ==》enter
  • 删除键 ==》delete
  • 退出键 ==》esc
  • 空格键 ==》space
  • 换行键 ==》tab(最好与keyup使用)
  • 上键 ==》up
  • 下键 ==》down
  • 左键 ==》left
  • 右键 ==》right

未提供的键盘别名可以用按键Key值,使用短横线命名法

系统修饰键

如ctrl,alt,shift,meta(win键)有特殊用法

配合keyup使用:

        按下系统修饰键,再按下并放开其他键时,触发事件

配合keydown使用:

        按下系统修饰键即触发事件

定制按键别名

语法:

        Vue.config.keyCodes.自定义按键名= 键码

计算属性

概念

属性:Vue实例中,data中的都认定为属性

计算属性:所需要的属性不存在,需要通过已有属性来计算获得

计算属性需要配置到Vue实例里,computed对象中

语法:

        const vm=new Vue({el:'.root',data:{属性},computed:{计算属性名:{get函数}}})

通过get()函数来进行计算,需要有return返回值,作为计算属性的值

get(调用时机):

  • 在初次读取计算属性时,get()调用
  • 计算属性所依赖属性数据发生变化时,也会调用

备注:

  • 也可以调用set()函数,进行数据改动
  • get()和set()函数的this均指向Vue实例
  • 计算属性会最终会出现在Vue实例上,直接调用即可

案例:

    <div class="root"><input type="text" v-model:value="xing"><br><input type="text" v-model:value="ming"><br><p>全名:{{quanming}}</p></div><script>const vm = new Vue({el: '.root',data: {xing: '张',ming: '三'},computed: {quanming: {get() {return this.xing + this.ming}}}})</script>

简写

在没有写set()函数时,可以使用简写

语法:

            computed: {计算属性名() {函数体}}
            computed: {quanming() {return this.xing + this.ming}}

监视属性

概念与语法

可以设置被监视的属性,当被监视属性发生改变时,会自行调用函数

写法1:

        const vm = new Vue({el: 'div',watch: {监视属性名: {immediate: 布尔值,//默认为false,是否初始化时调用deep: 布尔值,//默认为false,是否开启深度监视handler(newValue, oldValue) {//newValue为新值,oldValue为旧值函数体}}}})

写法2:

        vm.$watch('监视属性名', {immediate: 布尔值,//默认为false,是否初始化时调用deep: 布尔值,//默认为false,是否开启深度监视handler(newValue, oldValue) {//newValue为新值,oldValue为旧值函数体}})

在监视属性改变时,会调用handler()函数

深度监视 

配置deep: true时开启深度监视

Vue中watch默认不检测对象内部值的改变

开启深度监视可以检测对象内部值的改变

简写

当deep和immediate均没有配置时,可以简写

简写1:

        const vm = new Vue({el: 'div',watch: {监视属性名(newValue, oldValue): {//newValue为新值,oldValue为旧值函数体}}})

简写2:

        vm.$watch('监视属性名', function(newValue, oldValue){//newValue为新值,oldValue为旧值函数体})

计算属性与监听属性区别

  • computed相当于watch更加简单
  • computed能完成的,watch均能完成
  • watch能完成的,computed不一定能完成(watch可进行异步操作)

绑定样式

绑定class

1.字符串写法

直接使用v-bind来绑定样式

可以绑定事件,来动态改变类名

        <div class="main" :class="mood">{{text}}</div>
<head><style>.main {width: 100px;height: 100px;border: 1px solid black;}.test01 {background-color: aqua;}</style><script src="../vue.js"></script>
</head><body><div id="root"><div class="main" :class="mood">{{text}}</div></div><script>const vm = new Vue({el: '#root',data: {text: '111',mood: 'test01',}})</script>
</body>

2.数组写法

用于绑定多个样式

可以通过动态操作数组来控制类

<head><style>.work01 {font-size: 20px;}.work02 {color: aqua;}.work03 {font-style: italic;}</style><script src="../vue.js"></script>
</head><body><div id="root"><div class="main" :class="classArr">{{text}}</div></div><script>const vm = new Vue({el: '#root',data: {text: '111',classArr: ['work01', 'work02', 'work03']}})</script>
</body>

3.对象写法

用于绑定多个样式,并动态决定用与不用

控制对象中的布尔值,动态决定类的用与不用

<head><style>.work01 {font-size: 20px;}.work02 {color: aqua;}.work03 {font-style: italic;}</style><script src="../vue.js"></script>
</head><body><div id="root"><div class="main" :class="classObj">{{text}}</div></div><script>const vm = new Vue({el: '#root',data: {text: '111',classObj: {work01: true,work02: true,work03: true,}}})</script>
</body>

绑定style

1.直接绑定

直接使用v-bind来绑定样式

语法:

        : style = " { 属性(驼峰命名法) : xxx } "

        xxx为Vue示例中的data数据

    <div id="root"><div class="main" :style="{fontSize:fs}">{{text}}</div></div><script>const vm = new Vue({el: '#root',data: {text: '1111',fs:'20px'}})</script>

2.对象写法

    <div id="root"><div class="main" :style="styleObj">{{text}}</div></div><script>const vm = new Vue({el: '#root',data: {text: '1111',styleObj: {fontSize: '40px',backgroundColor: 'aqua'}}})</script>

3.数组写法

需要在数组中配置对象

    <div id="root"><div class="main" :style="styleArr">{{text}}</div></div><script>const vm = new Vue({el: '#root',data: {text: '1111',styleArr: [{fontSize: '40px',backgroundColor: 'aqua'},{color: 'blue'}]}})</script>

条件渲染

v-show

语法:

        v-show = “ 表达式 ”

        表达式值为布尔值

表达式值为false,元素被隐藏,display值为none

v-if

语法:

        v-if = “ 表达式 ”

        后可接v-else-if和v-else

        表达式值为布尔值

表达式值为false时,元素直接被删除,替换为空注释

    <div id="root"><div v-show="false">{{test01}}</div><div v-show="true">{{test01}}</div><br><div v-if="false">{{test02}}</div><div v-if="true">{{test02}}</div></div><script>const vm=new Vue({el:'#root',data:{test01:'111',test02:'222'}})</script>

 列表渲染

v-for遍历

遍历对象

语法:

        v-for = " ( value , key) in 对象名 "  或

        v-for = "  value  in 对象名 "  

        value获取属性值,key获取属性名

    <div id="root"><li v-for="(value,key) in Person">{{value}}----{{key}}</li></div><script>const vm=new Vue({el:'#root',data:{Person:{name:'Tom',age:18,shool:'sdau'}}})</script>

遍历数组 

语法:

        v-for = " ( value , item) in 数组名 "  或

        v-for = "  value  in 对象名 "  

        value获取值,item获取索引

    <div id="root"><li v-for="(value,item) in Arr">{{value}}----{{item}}</li></div><script>const vm = new Vue({el: '#root',data: {Arr: ['A','B','C']}})</script>

key的使用与作用

key的使用

在 v-for遍历 中要添加一个 key属性 

key值的选择,最好使用每条数据的唯一标识

例如ID,身份证,学号等等

如果不添加 key属性 则key值默认为数组或对象的序列号

    <div id="root"><li v-for="(p,item) in Person" :key="p.id">{{p.name}}---{{p.age}}</li></div><script>const vm=new Vue({el:'#root',data:{Person:[{id:'001',name:'wu',age:18},{id:'002',name:'liu',age:20},{id:'003',name:'zhao',age:19},]}})</script>

key的作用和虚拟DOM

虚拟DOM是Vue根据数据生成的

key是虚拟DOM对象的标识,可以理解成虚拟DOM对象的唯一ID

当数据发生改变时,Vue会根据新数据生成新虚拟DOM

新旧DOM会进行对比:

1.若有相同的key值:

  • 若虚拟DOM内容没有变,直接使用真实DOM生成页面
  • 若虚拟DOM内容变化,生成新真实DOM替换之前的

2.若没有相同的key值:

  • 直接建立真实DOM,生成页面 

Vue监视数据原理

基本

Vue会监视data中所有有层次的数据

被监视的对象,会添加get()和set()函数,以实现响应式

( get()和set()函数用自Object . defineProperty())

示例:

            data: {Person: {name: 'Tom',age: 18,shool: 'sdau'},Arr: ['A','B','C']}

注:数组中的数据没有进行监视,但数组本身被监视

如上图,Arr数组有get()和set()函数

如下图,Arr[0]以及其他数据没有get()和set()函数

关于对象

对象中的数据通过 get()和set()函数 监视

对象中后追加的属性,Vue不会进行监视,即不会有get()和set()函数

如果需要监视追加的属性,则需要用到 特定API

语法:

    Vue.set(对象名,属性名,属性值)  另一种写法this.$set(对象名,属性名,属性值)

对象名指被添加属性的对象,注意 ' '

示例:给Person对象添加sex属性,属性值为 男

                addSex() {//Vue.set(this.Person,'sex','男')  另一种写法this.$set(this.Person, 'sex', '男')}

用此API添加的属性,拥有get()和set()函数,会被监视

注:

        该API,不能给vm或vm的根数据对象(data等)添加属性

关于数组

 因为Vue中数组没有get()和set()函数

所有Vue通过其他方式,来实现数组数据的响应式

在数组中修改数据,必须使用以下方法:

  1. 使用API:push(),pop(),shift(),unshift(),splice(),sort(),reverse()
  2. 使用Vue.set() 或 vm.$set().
    Vue.set(数组名,序列,修改值)  另一种写法this.$set(数组名,序列,修改值)

只有使用以上方法数组数据才可以实现响应式

当然,也可以直接修改数组本身,因为数组本身有get()和set()函数

过滤器

定义:
        对要显示的数据进行特定格式化后再显示(用于一些简单的逻辑处理)

注册过滤器(两种方式):

        Vue.filters(过滤器名称,function(){函数体})//全局过滤器或new Vue({filters:{过滤器名称(){函数体}}})//局部过滤器

使用过滤器:

过滤器可以用于插值语法 和 v-bind指令

  • {{ xxx | 过滤器名称 }}
  • v-bind:属性 = " xxx | 过滤器名称 " 

常见内置指令

之前接触过的指令

指令作用简写
v-bind单向绑定解析表达式:xx
v-model双向数据绑定v-model="xx"
v-for遍历数组/对象/字符串
v-on绑定事件监听@
v-if / v-else条件渲染(控制节点是否存在)
v-show条件渲染(控制节点是否展示)

v-text指令

作用:
        向所在节点渲染文本

    <div id="root"><p>{{name}}</p><p v-text="name"></p><p v-text="name">1111</p></div><script>new Vue({el:'#root',data:{name:'zhao'}})</script>

注:
        v-text会替换掉节点中的内容

v-html指令

作用:
        向指定节点中渲染包含html结构的内容

        可以识别html结构

    <div id="root"><div v-html="test"></div></div><script>new Vue({el:'#root',data:{test:'<p>123456</p>'}})</script>

注(v-html有安全性问题):

  1.  在网站上动态渲染任意HTML非常危险,容易导致xss攻击
  2. 在可信内容上使用v-html,不用用在用户提交内容上

v-cloak指令

在网速非常慢的时候,可能会展示未经过Vue渲染的页面

因为网速慢,Vue会加载不出来

可以使用v-cloak指令配合CSS来解决

  • v-cloak没有值
  • v-cloak本质是一个属性
  • v-cloak在Vue加载完成后删除
    <style>[v-cloak]{display: none;}</style><div id="root"><div v-cloak>111</div></div>

v-once指令

  • v-once没有值
  • v-once所在节点只进行初次动态渲染
  • 初次动态渲染完成后,变为静态内容
  • 以后数据变化不会引起所在结构改变

v-pre指令

用于跳过其所在节点的编译过程

        <p v-pre>{{name}}</p>

自定义指令 

函数式

自定义指令可以通过配置到Vue实例里,directives对象中来实现

语法:

        new Vue({directives:{指令名(element,binding){函数体}}})

其中传入的参数:

element为绑定自定义指令标签的DOM对象

binding为DOM对象的相关属性

绑定自定义指令时要加v-

    <div class="root"><p v-test01>1111</p></div><script>const vm=new Vue({el:'.root',directives:{test01(element,binding){console.log(element,binding)}}})</script>

自定义指令中函数调用时机:

  • 指令与元素成功绑定时函数调用
  • 指令所在模板重新解析时函数调用

注:命名如果有多个单词,使用 - 链接

对象式

对象式自定义指令函数调用时机更加细致,会比函数时多一次调用

语法:

        new Vue({directives:{指令名:{bind(element,binding){函数体},inserted(element,binding){函数体},update(element,binding){函数体}}}})

传入的参数同函数式

函数调用时机:

  • bind函数:指令与元素绑定成功时调用
  • inserted函数:指令所在元素被插入页面时调用
  • update函数:指令指令所在模板重新解析时调用

全局自定义指令

通过在Vue实例中配置directives对象所设置的为局部指令

全局自定义指令语法:
        Vue.directive(指令名,配置对象)

        Vue.directive(指令名,回调函数)

    <div class="root"><div v-test03>33</div><div v-test04>44</div></div><script>Vue.directive('test03', {bind(element, binding) {console.log(element, binding)},inserted(element, binding) {console.log(element, binding)},update(element, binding) {console.log(element, binding)}})Vue.directive('test04',function(element, binding){console.log(element, binding)})</script>

生命周期

概念

生命周期 又名:生命周期回调函数,生命周期函数,生命周期钩子

生命周期本质上就是函数

Vue会在特殊时刻帮我们调用的一些特殊名称的函数

生命周期函数名字不可更改,其配置在Vue实例中,其中this指向Vue示例

示例(以mounted为例):

    <script>const vm = new Vue({el: '#root',mounted() {console.log(this)},})</script>

“Vue的一生”

创建(出生)

Vue刚刚创建,仅完成初始化,此时数据监测和数据代理创建还未开始;

初始化完成后,进行数据监测和数据代理创建时,会调用两个生命周期函数(不是Vue创建时)

此时 模板未解析

1.数据监测和数据代理之前,初始化后:

  • 调用beforeCreate函数
  • 此时无法通过vm访问data中的数据,methods中的方法
  • 因为数据监测和数据代理未完成

2.数据监测和数据代理之后,解析模板之前:

  • 调用created函数
  • 此时可以通过vm访问data中的数据,methods中的方法
  • 因为模板未解析,页面不会显示解析内容
挂载(生活)

挂载即把初始的真实DOM元素放到页面

在Vue解析完模板,生成虚拟DOM后,进行虚拟DOM转真实DOM

此时调用两个生命周期函数

1.解析完模板后,挂载完成前:

  • 调用beforeMount函数
  • 页面此时呈现未未经Vue编译的DOM
  • 所有对DOM的操作,最终都不会奏效

2.挂载完成后:

  • 调用mounted函数
  • 对DOM的操作有效,但尽量避免
  • 此时可以进行一些初始化操作,比如开启定时器,发送网络需求等
更新(颠覆三观)

在数据更新时,会调用两个生命周期函数

1.新虚拟DOM生成前:

  • 调用beforeUpdate函数
  • 此时Data数据是新的,但是页面没有进行更新

2.页面更新后:

  • 调用updated函数
  • 此时Data数据和页面都是新的
销毁(逝世)

Vue可以通过Vue.$destroy()来销毁

销毁时会调用两个生命周期函数

1.销毁前(回光返照):

  • 调用beforeDestroy函数
  • 此时Vue的所有配置都还可以使用,即将销毁
  • 一般在此阶段进行关闭定时器,取消订阅的收尾操作

2.销毁后(已寄):

  • 可以调用destroyed函数,但Vue以及没有

注意事项

常用生命周期钩子:

  1. mounted:初始化操作
  2. beforeDestroy:收尾操作

关于销毁Vue:

  • 销毁后自定义事件失效,但原生DOM事件依然有效
  • 一般不会使用beforeDestroy操作Data数据,因为用不到了

Vue组件化编程

组件

实现应用中局部功能代码资源集合

扒一张官网的图(下图):

在一个大盒子中可以分三个中盒子(灰色) ,中盒子又可以分成几个小盒子(深灰色)

这几个盒子中代码和资源的集合可以视为一个组件

作用:组件可以复用编码,简化项目编码

当应用中的功能都是多组件的方式来编写的,那这个应用就是一个组件化的应用

非单文件组件

特点:一个文件中包含多个组件

Vue使用组件有三步:

  1. 定义组件(创建组件)
  2. 注册组件
  3. 使用组件

定义组件(创建组件)

定义组件需要使用Vue.extend()在全局中进行定义

其中()中传入的内容与 new Vue()需要传入的几乎一模一样

区别:

  • 不写el配置:最终所有组件由vm中的el来决定服务于那个容器
  • data必须写出函数式:避免数据存在引用关系
  • 使用template配置组件结构

示例:

        //定义组件const Person = Vue.extend({template: `<div><p>{{name}}--{{age}}</p></div>`,data() {return {name: 'zhao',age: '18'}}})

注册组件

1.局部注册

在Vue实例中配置components对象

        const vm = new Vue({el: '#Root',//注册局部组件components: {Person: Person//简写:Person}})

2.全局注册

语法:

        Vue.component('组件名', 组件)

        //注册全局组件Vue.component('School', School)

使用组件

在HTML中编写组件标签即可

    <div id="Root"><!--使用组件--><Person></Person><br><School></School></div>

示例代码

<body><div id="Root"><!--使用组件--><Person></Person><br><School></School></div><script>//定义组件const Person = Vue.extend({template: `<div><p>{{name}}--{{age}}</p></div>`,data() {return {name: 'zhao',age: '18'}}})const School = Vue.extend({template: `<div><p>{{name}}--{{address}}</p></div>`,data() {return {name: 'sdau',address: '泰安'}}})//注册全局组件Vue.component('School', School)const vm = new Vue({el: '#Root',//注册局部组件components: {Person: Person//简写:Person}})</script>
</body>

注意事项

组件名
  • 组件名如果由多个单词组成,使用kebab-case命名法:my-school
  • 也可以使用CamelCase命名:MySchool,但是需要Vue脚手架
  • 可以使用name配置指定组件在开发者工具中呈现的名字
        const School = Vue.extend({name:'xxx',template: `<div><p>{{name}}--{{address}}</p></div>`,data() {return {name: 'sdau',address: '泰安'}}})

简写

        const School = Vue.extend(options)

简写为:

        const School = options

组件其他事项

组件的嵌套

组件可以注册在组件中,实现组件的嵌套

示例:

<body><div id="Root"><App></App></div><script>const School = Vue.extend({template: `<div>{{name}}--{{address}}</div>`,data() {return {name: 'sdau',address: '泰安'}}})const Person = Vue.extend({template: `<div>{{name}}--{{age}}</div>`,data() {return {name: 'zhao',age: 18}}})const App = Vue.extend({template: `<div><Person></Person><School></School></div>`,components: {School,Person}})const vm = new Vue({el: '#Root',components: {App}})</script>
</body>

VueComponent

组件的本质是一个名为VueComponent构造函数,由Vue.extend生成

在我们使用组件时,Vue会解析并创建出组件的实例对象

即Vue会帮我们调用 new VueComponent(options)

另外,每次调用Vue.extend,返回值都是一个全新的VueComponent

关于this指向:

  • 组件配置中,this指向均是【VueComponent实例对象】
  • new Vue()配置中,this指向均是【Vue实例对象】

一个内置关系

在Vue中,组件原型对象 的 原型 为Vue示例的 原型对象

即:VueComponent.prototype.__proto__===Vue.prototype

可以让组件实例对象可以访问到Vue原型上的属性和方法

单文件组件

特点:一个文件中只包含1个组件

将非单文件组件中的多个组件进行拆分,写到多个文件中,每个文件就是一个组件

每个组件文件的后缀为 .vue

通过ES6模块化语法进行导出和引入

导出 

组件文件写法:

其中使用 export default { } 来导出组件

<template><div>模板</div>
</template><script>//导出export default {Vue配置项};
</script><style>样式 /*可省略*/
</style>

示例:

<template><div class="test"><h2>{{ name }}--{{ address }}</h2><button @click="show">123456</button></div>
</template><script>
export default {name: "SchoolName",data() {return {name: "sdau",address: "山东泰安",};},methods: {show() {alert("123456");},},
};
</script><style>
.test {background-color: aqua;
}
</style>

引入

引入可以使用 import···from··· 来引入

import 组件名 from "组件地址";

示例:

<template><div><PersonName></PersonName><SchoolName></SchoolName></div>
</template><script>
import PersonName from "./components/PersonName.vue";
import SchoolName from "./components/SchoolName.vue";
export default {name: "App",components: {PersonName,SchoolName,},
};
</script>

ref属性

ref属性用来给元素或子组件注册引用信息(id属性的替代者

语法:

  • 标记(示例):<h1 ref="xxx">···<h1> 或 <组件名 ref="xxx">···</组件名>
  • 获取:this.$refs.xxx

关于获取值:

  • 应用在html标签上,获取真实DOM元素
  • 应用在组件标签上,获取组件示例对象
<template><div id="app"><img ref="img" alt="Vue logo" src="./assets/logo.png" /><HelloWorld ref="hello" msg="Welcome to Your Vue.js App" /><button @click="show">按钮</button></div>
</template><script>
import HelloWorld from "./components/HelloWorld.vue";export default {name: "App",components: {HelloWorld,},methods: {show() {console.log(this.$refs);//返回对象console.log(this.$refs.img);//返回真实DOMconsole.log(this.$refs.hello);//返回组件示例对象},},
};
</script>

配置项props

配置项props可以让组件接受外部传来的数据

当父组件引入其他组件,父组件所需数据子组件没有时,

可以使用配置项props,通过父组件给子组件数据赋值

是一种组件间的通信方式,将数据从父组件传递给子组件

传递与接收

1.传递方(父组件):

    <子组件名 数据名=" 值 "/>

将传入的值传递给子组件

2.接收方(子组件):

  props:['数据名']

接收到父组件传递来的数据

示例:

  • App.vue(传递方,部分代码):
<template><div id="app"><MyPerson name="zhao"/><!--传递--></div>
</template>
  • MyPerson(接收方,部分代码):
<template><div><h1>{{ name }}--{{ age }}</h1></div>
</template><script>
export default {name: "MyPerson",data() {return {age: 18,};},props:['name']//接收
};
</script>

接收的三种方法

接收数据共有三种方法:

1.只接收

  props:['name']

2.限制类型

  props:{name:String//限制name为字符串}

3.限制类型与必要性,指定默认值

  props: {name: {type: String, //限制name为字符串required: true, //必要性default: "zhao", //默认值},},

必要性:父组件必须传值

必要性与默认值一般不在一起使用,有矛盾

mixin(混入)

功能:将多个组件共用的配置,进行提取,成为一个混入对象,进行使用

定义混入

混入可以定义在另一个JS文件中

即多个组件都有的配置,提取到一个JS文件中

export const test={methods:{show(){console.log(this.name);}}
}

通过导出,以便于组件使用

使用混入

局部混入

在引入混入后,可以通过mixins配置项来使用混入

<template><div><h1>{{name}}--{{age}}</h1><button @click="show">123</button></div>
</template><script>
import {test} from './mixin.js'export default {name:'MyPerson',data(){return{name:'zhao',age:18}},mixins:[test]
}
</script>

全局混入

可以直接在App组件中引入混入,使用Vue.mixin(xxx)来进行全局混入

import {test} from './components/mixin'
Vue.mixin(test)

插件

功能:用于增强Vue

本质:插件本质上是一个对象,其中含有一个install方法

install的第一个参数是Vue,所有插件可以实现各种功能

定义插件

对象名.install = function(Vue){函数体
}

使用插件

Vue.use(对象名)

scoped样式

在Vue组件化编程中,每个组件的样式也会影响到其他的组件,产生冲突

作用:

        可以让样式在局部生效,防止冲突

写法:

        <style scoped>

组件自定义事件

组件自定义事件是一种组件间的通信方式,将数据从子组件传递给父组件

绑定

绑定自定义事件都是在父组件中

方法一

直接在父组件中,给子组件绑定事件

    <MyPerson @gainP="getPersonName" />

如上,为子组件MyPerosn绑定名为gainP的事件

触发事件调用getPersonName回调函数

方法二

在生命周期钩子中绑定,用到ref属性

    <MySchool ref="dome" />......mounted() {this.$refs.dome.$on("gainS", this.getSchoolName);},

如上,为子组件MySchool绑定名为gainS的事件

触发事件调用getSchoolName回调函数

整体代码示例(父组件):

<template><div id="app"><p>{{ PersonName }}//{{ SchoolName }}</p><MyPerson @gainP="getPersonName" /><MySchool ref="dome" /></div>
</template><script>
import MyPerson from "./components/MyPerson.vue";
import MySchool from "./components/MySchool.vue";
export default {name: "App",components: {MyPerson,MySchool,},data() {return {PersonName: "",SchoolName: "",};},methods: {getPersonName(test) {this.PersonName = test;},getSchoolName(test) {this.SchoolName = test;},},mounted() {this.$refs.dome.$on("gainS", this.getSchoolName);},
};
</script>

触发

触发自定义事件都是在子组件中

通过触发原生事件来触发自定义事件

语法:

      this.$emit("自定义事件名", 传入数据);

示例: 

  <button @click="givePerosnName">触发事件</button>......methods: {givePerosnName() {this.$emit("gainP", this.Name);},},

如上,触发按钮点击事件,调用givePerosnName函数

在givePerosnName函数中触发gainP自定义事件

并且传入数据this.Name

解绑

解绑事件也是在子组件中

语法:

      this.$off("自定义事件名");

 示例:

  <button @click="relieve">解绑事件</button>......methods: {relieve() {this.$off("gainP");},},

如上,触发按钮点击事件,调用relieve函数

在relieve函数中解绑gainP自定义事件

其他

  • 组件可以绑定原生DOM事件,但是需要 native 修饰符
  • 通过方法二来绑定事件时,回调函数要配置在methods中,或用箭头函数,这样this指向正常,为父组件。使用普通函数,this指向子组件。

全局事件总线

全局事件总线是一种组件之间的通信方式,可以用于任意组件间通信

其并非Vue所提供的方法,而是一种思路,所以写法不唯一

核心思想是找到一个各个组件均可进行通信的中介,来进行任意组件间的通信

虽然写法不唯一,但只记一种

安装全局事件总线

中介可以创建在Vue实例对象的原型上

通过生命周期钩子在Vue实例对象创建完成前安装

在main.js中

new Vue({render: h => h(App),beforeCreate() {Vue.prototype.$bus = this}
}).$mount('#app')

如上:创建名为$bus的中介

使用全局事件总线

接收

接收数据要在接收方组件中,给中介$bus绑定自定义事件

事件的回调配置在接收方组件中

  methods: {getPersonName(test) {this.PersonName = test;},},mounted() {this.$bus.$on('gainP',this.getPersonName)},

如上:

为$bus绑定gainP的自定义事件,函数回调在组件methods配置中

另外,最好在beforeDestroy生命周期钩子中,用$off解绑当前组件所用事件

提供

提供数据只需要在提供方触发$bus的自定义事件即可

      this.$bus.$emit("gainP", this.Name);

消息订阅与发布

消息订阅与发布是一种组件之间的通信方式,可以用于任意组件间通信

1.安装

需要安装pubsub

    npm i pubsub-js

2.引入

import pubsub from 'pubsub-js'

3.接收数据

  methods: {dome(){......}},mounted(){this.pid=pubsub.subscribe('xxx',this.dome)//订阅消息}

4.提供数据

    pubsub.publish('xxx',数据)

5.取消订阅

    PubSub.unsubscribe(pid)

插槽

作用:是一种组件间的通信方式,可以让父组件向子组件指定位置插入HTML结构

           是一种将数据从父组件传递给子组件的方式

默认插槽

父组件(传递方):

设置要传给子组件的HTML结构,需要在使用组件时,在组建标签内写入

    <MyTest><div>Hello World</div></MyTest><!--MyTest为组件名-->

子组件(接收方):

在子组件中需要进行定义插槽,确定传入HTML的插入位置

HTML结构会插入在<slot>标签的位置

<template><div><slot>默认内容</slot><!--如果没有传入HTML,则渲染slot标签内的默认内容--></div>
</template>

 具名插槽

当需要插入多个插槽时,可以用具名插槽

子组件(接收方):

子组件定义多个插槽,并配置name

<template><div><slot name=dome1>默认内容</slot><slot name=dome2>默认内容</slot></div>
</template>

父组件(传递方):

给传递的HTML结构配置solt,值为插槽的name值

    <MyDome><div slot='dome1'>Hello World</div><div slot='dome2'>Hello World</div></MyDome>

作用域插槽

当需要使用的data数据不在传递方父组件自身,而在子组件里时

子组件(接收方):

子组件在定义插槽时,将数据传入插槽中

<template><div><slot :word='word'>默认内容</slot></div>
</template><script>
export default {name: "TheDome",data() {return {word: "Hello World",};},
};
</script>

 父组件(传递方):

必须使用<template>标签,并在标签内配置scope

    <TheDome><template scope="scopeData"> <div>{{ scopeData.word }}</div></template></TheDome>

如上, 子组件传递的数据,以对象形式,给了scopeData

nextTick

语法:

      this.$nextTick(()=>{回调函数})

作用:

        在下一次DOM更新后执行回调

        用于改变数据后,基于更新后的新DOM进行操作时

Vue封装的过渡与动画

如图所示:

Vue封装的过渡与动画分为进入(enter)离开(leave)

进入和离开又分为起点过程中(active)终点(to)

类名

  • 元素进入:
  1. v-enter:进入起点
  2. v-enter-active:进入过程
  3. v-leave-to:进入终点
  • 元素离开:
  1. v-leave:离开起点
  2. v-leave-active:离开过程
  3. v-leave-to:离开终点

在Vue中添加过渡与动画,需要给Vue所配置的类添加样式

过渡/动画

过渡的添加,需要六种样式全部配置

.v-enter,
.v-leave-to {transform: translateX(-100%);
}
.v-enter-to,
.v-leave {transform: translateX(0);
}
.v-enter-active,
.v-leave-active {transition: 1s;
}

使用 <transition>标签将要进行过度的元素进行包裹

    <transition><div class="dome" v-show="xxx">111</div></transition>

被包裹的元素会自行执行样式中所写的过渡

动画的添加,只需要配置v-enter-active和v-leave-active即可,其他同过渡

.v-enter-active {animation: 1s test01;
}
.v-leave-active {animation: 1s test01 reverse;
}
@keyframes test01 {from {transform: translateX(-100%);}to {transform: translateX(0);}
}

多个元素过渡

相同样式:

多个元素,共用一个过渡,需要用 <transition-group>标签包裹

并且每个元素都要指定key值

    <transition-group> <div class="dome" v-show="xxx" key="1">111</div><div class="dome" v-show="xxx" key="2">222</div></transition-group>

不同样式:

多个元素,不共用一个过渡

要为<transition>标签配置name属性

    <transition name='test01'><div class="dome" v-show="xxx">111</div></transition>

在写样式时,类名中的v换成name值

例:

.test01-enter,
.test01-leave-to {transform: translateX(-100%);
}

Vue中的Ajax

Vue脚手架配置代理

配置代理可以解决开发环境 Ajax 跨域问题

在vue.config.js中添加配置

  devServer:{proxy:'xxx'//xxx为服务器基础路径}

优点:

  • 配置简单,请求资源时直接发给前端

缺点:

  • 不能配置多个代理
  • 不能控制请求是否走代理

在vue.config.js中添加配置

devServer:{proxy:{'/dome':{//匹配所有以'/dome'为开头的请求路径target:'xxx',//代理目标的基础路径changeOrigin:true,pathRewrite:{'^/dome':''}}}
}

changeOrigin值为true时,服务器收到请求头中host为服务器基础路径

changeOrigin值为flase时,服务器收到请求头中host为本地基础路径

默认值为true

Vuex

Vuex简介

概念

        专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间的通信方式,且适用于任意组件间通信。

        简而言之,当多个组件共享数据时,使用Vuex来管理这些共享数据

原理

如图,在Vuex中,封装有actions,mutations,state三个对象,由store统一管理(图未显示)

其中,actions用于响应组件,mutations用于修改数据,state用于存储数据

当组件调用dispatch时,会经过相当于门卫的actions,进行一些逻辑处理

当然也可以绕过actions,调用commit直接到mutations,进行相应数据的修改

在action中调用commit,会到mutations中进行相应数据的修改

搭建Vuex环境

安装Vuex

搭建Vuex环境首先需要在终端中安装Vuex

    npm i vuex

创建store文件

创建路径:src/store/index.js

文件内容:

//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)//准备actions对象————响应组件中用户动作
const actions = {}
//准备mutations对象————修改state中的数据
const mutations = {}
//准备state对象————存储数据
const state = {}//创建并暴露store
export default new Vuex.Store({actions,mutations,state
})

传入store配置

在main.js中创建vm时,传入store配置

import Vue from 'vue'
import App from './App.vue'
//引入store
import store from './store' Vue.config.productionTip = falsenew Vue({render: h => h(App),store
}).$mount('#app')

基本使用

组件

在组件中,通过调用dispatch,来触发action

语法:

      this.$store.dispatch('函数名', 数据);

示例: 

  methods: {add() {this.$store.dispatch('add', this.number);//将会触发actions中的add函数,并把this.number传给actions},},

也可以通过调用commit,直接到 mutations中

  methods: {add() {this.$store.commit('add', this.number);//将会触发mutations中的add函数,并把this.number传给mutations},},

actions

在actions中,可以进行一些逻辑处理(如if判断等),然后调用commit

//准备action对象————响应组件中用户动作
const actions = {add(context, value) {context.commit('ADD', value)},
}

在组件中,触发actions的add函数,函数用两个参数

  • context封装有dispatch函数,commit函数,state对象等
  • context中dispatch函数用于调用其他actions中的函数
  • context中commit函数用于触发mutations
  • context中state数据对象,用于进行逻辑处理
  • value则是组件传入的数据

关于commit函数

        context.commit('ADD', value)

将会触发mutations中的ADD函数,并把tvalue传给mutations

mutations

在mutations,进行state的数据处理

//准备mutations对象————修改state中的数据
const mutations = {ADD(state, value) {state.sum += value},
}

其中的ADD函数传入两个参数:state数据对象和actions传入的value

state

state用于存储数据

//准备state对象————存储数据
const state = {sum: 0,
}

回到组件

在组件中,使用 $store.state 即可使用Vuex中的数据

    <div>和为:{{ $store.state.sum }}</div>

getters的使用

概念:

        当state中的数据需要经过加工后再使用时,可以使用getters进行加工

        类似于计算属性,可以当作Vuex中的计算属性

使用:

在index.js中追加getters配置

//准备getters对象————加工数据
const getters = {multiple(state) {return state.sum * 10}
}

并暴露出去

//创建并暴露store
export default new Vuex.Store({actions,mutations,state,getters
})

在组件中,使用 $store.getters 即可使用Vuex中加工后的数据

    <div>10倍和为:{{ $store.getters.multiple }}</div>

map方法

mapState方法

用于映射state中的数据,将其映射为组件中的计算属性

如下传统方法,在组件中,一直使用 $store.state获取数据显得十分麻烦

    <div>和为:{{ $store.state.sum }}</div><div>学校:{{ $store.state.school }}</div><div>姓名:{{ $store.state.name }}</div>

可以直接借助mapState生成计算属性

语法(两种写法)

    //对象写法mapState({ sum: "sum", school: "school", name: "name" }),//或//数组写法mapState(["sum", "school", "name"]),

内容

  mounted(){console.log(mapState({sum:'sum',school:'school',name:'name'}));}

其输出为一个对象,且都是函数,故需要放在计算属性中

使用

import { mapState } from "vuex";
  computed: {//对象写法...mapState({ sum: "sum", school: "school", name: "name" }),},computed: {//数组写法...mapState(["sum", "school", "name"]),},
    <div>和为:{{ sum }}</div><div>学校:{{ school }}</div><div>姓名:{{ name }}</div>

mapGetters方法

用于映射getters中的数据,将其映射为组件中的计算属性

用法与mapState方法无区别

import { mapGetters } from "vuex";
  computed: {//对象写法...mapGetters({ multiple: "multiple" }),},computed: {//数组写法...mapGetters(["multiple"]),},
    <div>10倍和为:{{ multiple }}</div>

mapActions方法

如下传统方法,使用$store.dispatch与actions对话,显得特**烦人

  methods: {add() {this.$store.dispatch("add", this.number);},sub() {this.$store.dispatch("sub", this.number);},addOdd() {this.$store.dispatch("addOdd", this.number);},addWait() {this.$store.dispatch("addWait", this.number);},},

可以靠mapActions方法来解决,省略$store.dispatc,实现组件与actions对话

其语法与mapState无异

内容

  mounted() {console.log(mapActions({ add: "add", sub: "sub" }));},

 其输出也为一个对象,且都是函数,需要放在methods配置中

使用

注意:需要手动在绑定事件时传参!

import { mapActions } from "vuex";
  methods: {//对象写法...mapActions({add: "add",sub: "sub",addOdd: "addOdd",addWait: "addWait",}),},methods: {//数组写法...mapActions(["add", "sub", "addOdd", "addWait"]),},
    <button @click="add(number)">+</button><button @click="sub(number)">-</button><button @click="addOdd(number)">为奇数时加</button><button @click="addWait(number)">一秒钟后加</button>

mapMutations方法

省略$store.commit,实现组件与actions对话

用法与mapActions方法无异

import { mapMutations } from "vuex";
  methods: {//对象写法...mapMutations({add: "add",sub: "sub",addOdd: "addOdd",addWait: "addWait",}),},methods: {//数组写法...mapMutations(["add", "sub", "addOdd", "addWait"]),},

模块化和命名空间

让代码更好维护,让多种数据分类更加明确

修改store

//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)const Count01 = {namespaced: true,//开启命名空间actions: {...},mutations: {...},state: {...},getters: {...}
}const Count02 = {namespaced: true,//开启命名空间actions: {...},mutations: {...},state: {...},getters: {...}
}//创建并暴露store
export default new Vuex.Store({modules: {Count01,Count02},
})

不使用map方法

<template><div><!--读取state数据--><p>数:{{ $store.state.Count01.number }}</p><br /><!--读取getters数据--><p>10倍为:{{ $store.getters['Count01/multiple'] }}</p><br /><button @click="add(1)">+1</button><br /><br /><button @click="addIf(1)">为奇数+1</button></div>
</template><script>
export default {name: "TheCount01",methods: {add(value) {//调用committhis.$store.commit("Count01/ADD", value);},addIf(value) {//调用dispatchthis.$store.dispatch("Count01/addIf", value);},},
};
</script>

使用map方法

<script>
import { mapState, mapGetters, mapActions, mapMutations } from "vuex";
export default {name: "TheCount02",computed: {//读取state数据...mapState("Count02", ["number"]),//读取getters数据...mapGetters("Count02", ["multiple"]),},methods: {//调用dispatch...mapActions("Count02", ["addIf"]),//调用commit...mapMutations("Count02", ["ADD"]),},
};
</script>

路由

路由的理解

路由就是一组 key-value 的对应关系

多个路由由路由器进行管理

Vue中通过vue-router插件来实现路由

基本路由

创建router文件

创建路径:src/router/index.js

示例:

//引入VueRouter
import VueRouter from "vue-router";
//引入组件
import TheTest01 from '../pages/TheTest01'
import TheTest02 from '../pages/TheTest02'//创建并暴露router实例对象
export default new VueRouter({routes: [{path: '/test01',component: TheTest01},{path: '/test02',component: TheTest02},]
})

创建的router示例对象中,需要配置一个routers数组,数组存储对象

path值为路由中的key值,component值为组件

组件需要进行引入

安装与应用vue-router插件

搭建vue-router环境首先需要在终端中安装vue-router

npm i vue-router

另外,需要在main.js中应用插件

import Vue from 'vue'
import App from './App.vue'//引入VueRouter
import VueRouter from 'vue-router'
//应用VueRouter
Vue.use(VueRouter)
//引入路由器
import router from './router/index'Vue.config.productionTip = falsenew Vue({render: h => h(App),router: router
}).$mount('#app')

注意在main.js中引入路由器,即router文件

实现组件切换

    <div><div class="a"><router-link active-class="active" to="/test01">test01</router-link></div><div class="a"><router-link active-class="active" to="/test02">test02</router-link></div></div><div><router-view></router-view></div></div>

使用<router-link>标签,实现切换,必需配置to以确定切换的页面

active-class可以配置类名

<router-view>标签,用于指定切换页面的展示位置

<router-view>标签本质是<a>标签

注意点

  1. 路由组件一般存放在pages文件夹中,一般组件存放在components文件夹中
  2. 切换后,未显示的组件默认被销毁,展示时在进行挂载
  3. 每个组件都有独属于自身的$router属性,存储自己的路由信息
  4. 整个应用只有一个routers,可以通过组件的$router属性获取

多级路由

多级路由就是实现路由的嵌套

在router文件中,使用children配置项

    routes: [{path: '/dome01',component: TheDome01},{path: '/dome02',component: TheDome02,//通过children配置子级路由children:[{path:'childdome01',//注意不要写/component:ChildDome01},{path:'childdome02',//注意不要写/component:ChildDome02},]},]

在组件(子组件)中实现跳转要写完整路径

    <div><router-link active-class="active" to="/dome02/childdome01">child01</router-link></div><div><router-link active-class="active" to="/dome02/childdome02">child02</router-link></div>

路由中的query参数

query参数是以路由为媒介,给路由组件传递数据的

传递方

        <router-linkactive-class="active":to="{//注意引号!!path: '/test02',query: {words: 'test02',},}">test02</router-link>

在<router-link>标签中,to配置项写成对象形式,里面写有query对象

query对象中的参数既是传递的数据

另外,也可以使用to的字符串写法,无需配置query,同样可以达到目的

        <router-link active-class="active" to="/test01?words=test01">test01</router-link>
        <router-link active-class="active" :to="`/test01?words=${test01}`">test01</router-link>

接收方(路由组件)

使用$route.query.xxx来接收数据

  <div><p>{{$route.query.words}}</p></div>

虽说是路由中的query参数,但是路由只是一个媒介

传递方组件的数据通过路由传递给路由组件

在此过程中,router文件不需要进行任何修改

命名路由

作用:用于简化路由的跳转

          主要在多级路由中展现其作用

在router文件中,使用name配置项

            children:[{path:'childdome01',//注意不要写/component:ChildDome01,name:'child1'//命名},]

组件中,在<router-link>标签中,to配置项同添加query时一样,需要写成对象形式

      <router-link active-class="active" :to="{name:'child1'}">child01</router-link>

可以配合query配置传递参数

路由中的params参数

params参数和query参数一样,是以路由为媒介,给路由组件传递数据的

路由器修改

在router文件中,要事先使用占位符声明接收参数

            children:[{path:'childdome01/:words',//使用占位符什么接收params参数component:ChildDome01,name:'child1'},]

如上,意为会传递一个名为words的参数

传递方

字符串写法:

直接使用 / 进行拼接

      <router-link active-class="active" :to="`/dome02/childdome02/text2`">child02</router-link>

对象写法:

配置params,并且不可以用path,而是用name

      <router-link active-class="active" :to="{name:'child1',params:{words:'text1'}}">child01</router-link>

接收方(路由组件)

使用$route.params.xxx来接收数据

  <div class="dome"><p>{{$route.params.words}}</p></div>

路由中的props配置

作用:配合query和params参数,让路由组件更方便收到参数

在接收方路由组件中,以$route.params.xxx或$route.query.xxx来接收数据显得特别麻烦

可以在router文件中配置props解决

方法一:

                {path:'childdome01/:words',component:ChildDome01,name:'child1',//值为对象,对象中所有key-value组合通过props传给路由组件props:{name:'test'}},

方法二:

                {path:'childdome01/:words',//使用占位符什么接收params参数component:ChildDome01,name:'child1',//值为布尔值,为true时,把路由收到的所有params参数传给路由组件props:true},

方法三:

                {path:'childdome01/:words',//使用占位符什么接收params参数component:ChildDome01,name:'child1',//为函数,返回值传给路由组件props(route){return{test:route.query.words}}},

replace属性

浏览器的历史记录有两种写入方式:

  • push:追加历史记录
  • replace:覆盖历史记录

追加上的历史记录可以通过点击上图 ← 返回

历史记录被覆盖后就无法返回

路由跳转默认为push,即可以返回

在<router-link>标签中添加replace属性,可以改为replace

      <router-link active-class="active" to="/dome02" replace>dome02</router-link>

编程式路由

作用:无需使用<router-link>标签,即可实现路由的跳转

  methods:{show01(){this.$router.push({path:'/test01'})},show02(){this.$router.replace({path:'/test02'})},}

通过this.$router.push和this.$router.replace两个API来实现

分别以追加历史记录和覆盖历史记录的方式进行跳转路由

其里面的配置同to的对象写法

另外,如果配置name,则name为路由组件的name

其他API:

  • this.$router.forward() 前进
  • this.$router.back()     后退
  • this.$router.go()         传入一个整数,正值则前进,负值后退,跳转数为传入数

缓存路由组件

路由组件在切走后会被销毁

缓存路由组件可以使路由组件在切走后保持挂载,不被销毁

将<router-view>标签包裹在<keep-alive>标签中即可

      <keep-alive include="test01"><router-view></router-view></keep-alive>

<keep-alive>标签中的include属性为保持挂载的路由组件

不配置默认全部保持挂载,有多个时写成对象的形式

路由中特有的生命周期钩子

路由中有两个特有的生命周期钩子

  • activated()        路由组件激活时触发

  • deactivated()    路由组件切走后触发

注意:只有在<keep-alive>标签包裹下有用!

路由守卫

作用:对路由进行权限控制

分类:全局守卫,独享守卫,组件内守卫

全局守卫

全局守卫分为前置守卫和后置守卫

router文件更改

使用全局守卫,需要用到router的API,故不可用以下方式暴露

export default new VueRouter({......
})

 应改为如下代码

const router = new VueRouter({......
})export default router

meta配置

每个路由可以配置meta,这是一个可以让程序员自由传值的配置,meta是一个对象

使用路由守卫需要判断路由是否需要进行权限控制

可以在meta中添加一个布尔值,用于判断

const router = new VueRouter({routes: [{path: '/Person',component: ThePerson,meta: { isAuth: true }},]
})

全局守卫用法

1.全局前置守卫

初始化时执行,以及每次路由切换前执行

router.beforeEach((to, from, next) => {if (to.meta.isAuth) {//判断路由是否需要进行权限控制if (localStorage.getItem('test') === 'xxx') {//判断权限,权限控制的具体规则next()//放行} else {console.log('无权限');}} else {next()//放行}
})

全局前置守卫使用router.beforeEach(),传值为一个函数

函数传三个参数:to, from, next

to, from为对象,分别存储着 切换到的路由组件信息 和 切换走的路由组件信息

next为一个函数,调用时放行,进行路由的切换

2.全局后置守卫

初始化时执行,以及每次路由切换后执行

router.afterEach((to, from)=>{console.log(to, from);
})

一般情况下不用,只需要传递to和from两个参数

因为以及切换完,无需使用next

独享守卫

独享守卫是单独配置在某个路由中的

用于判断某个路由是否需要权限控制

除使用的API外,其他与前置守卫无区别

const router = new VueRouter({routes: [{path: '/Person',component: ThePerson,meta: { isAuth: true },beforeEnter(to, from, next) {if (to.meta.isAuth) {//判断路由是否需要进行权限控制if (localStorage.getItem('test') === 'xxx') {//判断权限,权限控制的具体规则next()//放行} else {console.log('无权限');}} else {next()//放行}}},]
})

组件内守卫

组件内守卫分为进入守卫和离开守卫

进入守卫,在通过路由进入某个路由组件时调用

离开守卫,在通过路由离开某个路由组件时调用

需要写在路由组件中,用法同全局守卫

    //进入守卫beforeRouteEnter(to, from, next){console.log(to, from, next);},//离开守卫beforeRouteLeave (to, from, next) {console.log(to, from, next);}

路由器两种工作模式

对于一个url来说,#后面的内容就是其hash值

hash值不会包含着http请求中,即hash值不会传递给服务器

路由器有两种工作模式:

1.hash模式

  • 地址中永远带着 #
  • 地址可能被第三方App标记为不合法
  • 兼容性高

2.history模式

  • 地址中不带着 #
  • 兼容性比hash模式差
  • 部署后需要后端修404问题

路由默认为hash模式

修改为history模式如下代码:

const router = new VueRouter({mode:'history',.......
})

相关文章:

Vue2学习记录

前言 这篇笔记&#xff0c;是根据B站尚硅谷的Vue2网课学习整理的&#xff0c;用来学习的 如果有错误&#xff0c;还请大佬指正 Vue核心 Vue简介 Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的 JavaScript 框架。 它基于标准 HTML、CSS 和 JavaScr…...

TMS FNC UI Pack 5.4.0 for Delphi 12

TMS FNC UI Pack是适用于 Delphi 和 C Builder 的多功能 UI 控件的综合集合&#xff0c;提供跨 VCL、FMX、LCL 和 TMS WEB Core 等平台的强大功能。这个统一的组件集包括基本工具&#xff0c;如网格、规划器、树视图、功能区和丰富的编辑器&#xff0c;确保兼容性和简化的开发。…...

Redis主从架构

Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的、高性能的键值对存储系统&#xff0c;广泛应用于缓存、消息队列、实时分析等场景。为了提高系统的可用性、可靠性和读写性能&#xff0c;Redis提供了主从复制&#xff08;Master-Slave Replication&#xf…...

logback动态获取nacos配置

文章目录 前言一、整体思路二、使用bootstrap.yml三、增加环境变量四、pom文件五、logback-spring.xml更改总结 前言 主要是logback动态获取nacos的配置信息,结尾完整代码 项目springcloudnacosplumelog&#xff0c;使用的时候、特别是部署的时候&#xff0c;需要改环境&#…...

KETTLE安装部署V2.0

一、前置准备工作 JDK&#xff1a;下载JDK (1.8)&#xff0c;安装并配置 JAVA_HOME 环境变量&#xff0c;并将其下的 bin 目录追加到 PATH 环境变量中。如果你的环境中已存在&#xff0c;可以跳过这步。KETTLE&#xff08;8.2&#xff09;压缩包&#xff1a;LHR提供关闭防火墙…...

[RabbitMQ] 保证消息可靠性的三大机制------消息确认,持久化,发送方确认

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…...

aws服务--机密数据存储AWS Secrets Manager(1)介绍和使用

一、介绍 1、简介 AWS Secrets Manager 是一个完全托管的服务,用于保护应用程序、服务和 IT 资源中的机密信息。它支持安全地存储、管理和访问应用程序所需的机密数据,比如数据库凭证、API 密钥、访问密钥等。通过 Secrets Manager,你可以轻松管理、轮换和访问这些机密信息…...

Java设计模式笔记(一)

Java设计模式笔记&#xff08;一&#xff09; &#xff08;23种设计模式由于篇幅较大分为两篇展示&#xff09; 一、设计模式介绍 1、设计模式的目的 让程序具有更好的&#xff1a; 代码重用性可读性可扩展性可靠性高内聚&#xff0c;低耦合 2、设计模式的七大原则 单一职…...

Unity3d C# 实现一个基于UGUI的自适应尺寸图片查看器(含源码)

前言 Unity3d实现的数字沙盘系统中&#xff0c;总有一些图片或者图片列表需要点击后弹窗显示大图&#xff0c;这个弹窗在不同尺寸分辨率的图片查看处理起来比较麻烦&#xff0c;所以&#xff0c;需要图片能够根据容器的大小自适应地进行缩放&#xff0c;兼容不太尺寸下的横竖图…...

【es6进阶】vue3中的数据劫持的最新实现方案的proxy的详解

vuejs中实现数据的劫持,v2中使用的是Object.defineProperty()来实现的&#xff0c;在大版本v3中彻底重写了这部分&#xff0c;使用了proxy这个数据代理的方式&#xff0c;来修复了v2中对数组和对象的劫持的遗留问题。 proxy是什么 Proxy 用于修改某些操作的默认行为&#xff0…...

w~视觉~3D~合集3

我自己的原文哦~ https://blog.51cto.com/whaosoft/12538137 #SIF3D 通过两种创新的注意力机制——三元意图感知注意力&#xff08;TIA&#xff09;和场景语义一致性感知注意力&#xff08;SCA&#xff09;——来识别场景中的显著点云&#xff0c;并辅助运动轨迹和姿态的预测…...

IT服务团队建设与管理

在 IT 服务团队中&#xff0c;需要明确各种角色。例如系统管理员负责服务器和网络设备的维护与管理&#xff1b;软件工程师专注于软件的开发、测试和维护&#xff1b;运维工程师则保障系统的稳定运行&#xff0c;包括监控、故障排除等。通过清晰地定义每个角色的职责&#xff0…...

一文学习开源框架OkHttp

OkHttp 是一个开源项目。它由 Square 开发并维护&#xff0c;是一个现代化、功能强大的网络请求库&#xff0c;主要用于与 RESTful API 交互或执行网络通信操作。它是 Android 和 Java 开发中非常流行的 HTTP 客户端&#xff0c;具有高效、可靠、可扩展的特点。 核心特点 高效…...

自研芯片逾十年,亚马逊云科技Graviton系列芯片全面成熟

在云厂商自研芯片的浪潮中&#xff0c;亚马逊云科技无疑是最早践行这一趋势的先驱。自其迈出自研芯片的第一步起&#xff0c;便如同一颗石子投入平静的湖面&#xff0c;激起了层层涟漪&#xff0c;引领着云服务和云上算力向着更高性能、更低成本的方向演进。 早在2012年&#x…...

Stable Diffusion 3 部署笔记

SD3下载地址&#xff1a;https://huggingface.co/stabilityai/stable-diffusion-3-medium/tree/main https://huggingface.co/spaces/stabilityai/stable-diffusion-3-medium comfyui 教程&#xff1a; 深度测评&#xff1a;SD3模型表现如何&#xff1f;实用教程助你玩转Stabl…...

微信小程序WXSS全局样式与局部样式的使用教程

微信小程序WXSS全局样式与局部样式的使用教程 引言 在微信小程序的开发中,样式的设计与实现是提升用户体验的关键部分。WXSS(WeiXin Style Sheets)作为微信小程序的样式表语言,不仅支持丰富的样式功能,还能通过全局样式与局部样式的灵活运用,帮助开发者构建美观且易于维…...

Docker 部署 MongoDB

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f343; vue-uniapp-template &#x1f33a; 仓库主页&#xff1a; GitCode&#x1f4ab; Gitee &#x1f…...

Unity图形学之法线贴图原理

1.正常贴图&#xff1a;RGBA 4通道 每个通道取值范围 0-255 贴图里面取值是 0-1 2.法线贴图&#xff1a;法线怎么存入正常贴图的过程 每个通道里面存储的是一个向量(x,y,z,w) 通常我们会对应xyzw为rgba 存储值的范围也是0-1向量的取值范围是 -1到1法线怎么存入正常贴图的过程&…...

爬虫开发(5)如何写一个CSDN热门榜爬虫小程序

笔者 綦枫Maple 的其他作品&#xff0c;欢迎点击查阅哦~&#xff1a; &#x1f4da;Jmeter性能测试大全&#xff1a;Jmeter性能测试大全系列教程&#xff01;持续更新中&#xff01; &#x1f4da;UI自动化测试系列&#xff1a; SeleniumJava自动化测试系列教程❤ &#x1f4da…...

JVM系列之OOM观测准备

OOM, 全称 “Out Of Memory”&#xff0c;即内存用完的意思。JVM 因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时&#xff08;可分配内存大于需要分配的内存&#xff09;, 就会抛出 java.lang.OutOfMemoryError。在实际的生产应用中&#xff0c;一旦…...

Qt | 开发技能提升档次哈

点击上方"蓝字"关注我们 01、Creator常用快捷键 >>> F1 查看帮助 F2 跳转到函数定义 Shift+F2 声明和定义之间切换 F3 查找下一个 F4 头文件和源文件之间切换 Ctrl+1 欢迎模式 Ctrl+2 编辑模…...

D79【 python 接口自动化学习】- python基础之HTTP

day79 requests模块发送请求 学习日期&#xff1a;20241125 学习目标&#xff1a;http定义及实战 -- requests模块进行get请求带参数&requests模块进行post请求 学习笔记&#xff1a; requests模块进行get请求 import requestsparams{"shouji":"130999…...

C++【日志模块中的writer类】前文中 循环队列用法

用到前文中的循环队列模板 /* ** File name: LogWriter.h ** Author: ** Date: 2024-11-4 ** Brief: 日志写入类 ** Note: 日志写入类&#xff0c;负责将日志写入文件和连接客户端。 ** Copyright (C) 1392019713qq.com All rights reserve…...

Linux:文件管理(一)——文件描述符fd

目录 一、文件基础认识 二、C语言操作文件的接口 1.> 和 >> 2.理解“当前路径” 三、相关系统调用 1.open 2.文件描述符 3.一切皆文件 4.再次理解重定向 一、文件基础认识 文件 内容 属性。换句话说&#xff0c;如果在电脑上新建了一个空白文档&#xff0…...

【C++初阶】第3课—类和对象(类的默认成员函数)

文章目录 1. 类的默认成员函数2. 构造函数3. 拷贝构造函数3.1 传值传参3.2 传值返回3.3 深拷贝和浅拷贝3.4 总结 4. 析构函数5. 赋值运算符重载5.1 运算符重载5.2 赋值运算符重载5.3 日期类的实现 6. 取地址运算符重载6.1 const 成员函数6.2 取地址运算符重载 1. 类的默认成员函…...

uni-app初学笔记:文件路径与作用

components:可复用的组件pages:页面&#xff08;可见/不可见&#xff09;static:静态资源&#xff0c;存放图片视频等 &#xff08;相当于vue项目的 assets&#xff09;mainjs:Vue初始化入口文件App.vue:应用配置&#xff0c;用来配置App全局样式以及监听pages.json :配置页面路…...

小程序-使用 iconfont 图标库报错:Failed to load font

官方默认可以忽略此错误&#xff0c;在清除缓存后首次刷新会显示此错误&#xff0c;重新渲染错误消失 解决方法&#xff1a; 在 iconfont 图标库选择项目设置 选中 Base64 保存&#xff0c;重新点击链接 -> 复制代码到项目中 操作步骤&#xff1a;...

【计网】自定义协议与序列化(一) —— Socket封装于服务器端改写

&#x1f30e; 应用层自定义协议与序列化 文章目录&#xff1a; Tcp协议Socket编程 应用层简介 序列化和反序列化       重新理解read/write/recv/send及tcp的全双工       Socket封装       服务器端改写 &#x1f680;应用层简介 我们程序员写的一个个解决…...

速度革命:esbuild如何改变前端构建游戏 (1)

什么是 esbuild&#xff1f; esbuild 是一款基于 Go 语言开发的 JavaScript 构建打包工具&#xff0c;以其卓越的性能著称。相比传统的构建工具&#xff08;如 Webpack&#xff09;&#xff0c;esbuild 在打包速度上有着显著的优势&#xff0c;能够将打包速度提升 10 到 100 倍…...

大语言模型---什么是注意力机制?LlaMA 中注意力机制的数学定义

摘要 注意力机制&#xff08;Attention Mechanism&#xff09;是一种在深度学习和人工智能中广泛使用的技术&#xff0c;旨在使模型在处理信息时能够重点关注重要的部分&#xff0c;从而提升任务的效率和精度。它最初应用于自然语言处理&#xff08;NLP&#xff09;&#xff0…...

惠州做棋牌网站建设哪家公司收费合理/百度营销后台

文章目录**1. 概述****2. String类的特点****3. 常见操作方法****3.1 构造方法****3.2 判断功能****3.3 获取功能****3.4 转换功能****3.5 其他功能****4. String类练习**4.1 把数组中的数据按照指定个格式拼接成一个字符串**4.2 字符串反转****4.3 统计大串中小串出现的次数**…...

在腾讯云怎样建设网站/荆州seo推广

本文地址&#xff1a;http://www.cnblogs.com/archimedes/p/c-opensource-project.html&#xff0c;转载请注明源地址。 本篇文章主要总结一些C开源项目&#xff0c;有些是很著名的&#xff0c;有些则比较生僻 1.Webbench Webbench是一个在linux下使用的非常简单的网站压测工具…...

淄博市人民政府门户网站建设工作调研报告/建网站的流程

目录 - - - - -- - - - -- - - - -- - - - -- - - - -- - - - -- - - - -- - - - -- - - - -- - - - -- - - - - 1. 基础类业务 2. 融资融券业务 3. 投资银行业务 4. 投资管理业务 5. 资产管理业务 6. 券商与商业银行的合作业务 7. 券商与信托公司的合作业务 8. 多金融…...

企业网站建设的方案ppt/沈阳网络营销推广的公司

添加一个maven管理的工程后&#xff0c;需要配置jdk&#xff0c;但是右键工程的属性后&#xff0c;没有出现java path build。 网上查了一下&#xff0c;总结方法如下&#xff1a;找到工程下的.project文件&#xff0c;打开&#xff0c;添加红色框图中的内容。 最后&#xff0c…...

制作个人免费网站展示设计/武汉网优化seo公司

首先 下载并安装好网易MuMu模拟器: https://mumu.163.com/mac/index.html 运行网易MuMu,打开后在首页打开设置->开发者选项->打开USB调试模式 如果已经打包好的apk文件&#xff0c;则直接将apk文件拖动到模拟器窗口&#xff0c;apk会被自动安装 ADB connect 这里需要说明…...

婚纱摄影网站应该如何做优化/搜索引擎营销的优缺点及案例

【C#】分享一个可灵活设置边框的Panel ---------------------------更新&#xff1a;2014-05-19--------------------------- 优化了一下逻辑&#xff0c;就是既然可以通过设置BorderSideNone来不显示边框&#xff0c;那么再设计一个BorderMode.None就显得多余&#xff0c;即Bo…...