Vue

Vue

初识Vue:
1.想要Vue工作,就必须要创建一个Vue实例,且要传入一个配置对象
2.demo容器里的代码任然符合html规范,只不过加入了一些Vue语法
3.demo容器里的代码被称为【Vue模板】
4.Vue实例和容器是一一对应的
5.真实开发中只会有一个Vue实例,并且会配合着组件一起使用
6.中的xxx要写js表达式,且xxx会自动读取到data里的所有属性
7.一旦data中的数据发生改变,那么页面中用到该数据的地方都会自动更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>初识Vue</title>
    <!-- 修改页签icon logo -->
    <link rel="shortcut icon" type="image/x-icon" href="../images/vue.png"></link>
    <!-- 引入vue -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    // 准备一个容器
    <div class="demo">
        <h1>今天是{{date}},这是{{name}}的第一个vue程序</h1>
    </div>
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
        console.log(Vue.config)
            //创建Vue实例
        new Vue({
            el: '.demo',
            data: {
                date: '2022/8/11',
                name: 'jyd'
            }
        })
    </script>
</body>
</html>

模板语法

插值语法

用于解析标签体内容
写法:,xxx是js表达式,且xxx会自动读取到data里的所有属性

指令语法

用于解析标签(包括:标签属性,标签体内容,绑定事件…)
举例:v-bind:href=”xxx” 或 简写为 :href=”xxx” ,xxx同样要写出js表达式的形式
Vue中有很多指令,都是v-xxx

数据绑定

Vue中有两种数据绑定的方式:
1.单向绑定(v-bind):数据只能从 data 流向页面
2.双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向 data

双向绑定一般只应用在表单类元素上(如:input, select)
v-model:value 可以简写成 v-model ,因为v-model默认收集的就是value值

1
<input type="text" v-model:value="name" class="text">

el和data的两种写法

数据代理

通过一个对象代理对另一个对象中的属性的操作(读/写)
1.Vue中的数据代理:通过 vm 对象来代理data中属性的操作
2.Vue中数据代理的好处:更加方便地操作data中的数据
3.基本原理:
    通过Object.defineProperty() 把data对象中的所有属性都添加到vm上
    为每一个添加到vm上的属性,都指定一个getter/setter
    在getter/setter 内部去操作(读/写)data中对应的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>何为数据代理</title>
    </head>
    <body>
        <script type="text/javascript" >
            let obj = {x:100}
            let obj2 = {y:200}
            // 给obj2添加了x属性,实际指向obj.x
            // 通过修改obj2.x的值达到修改obj.x的值
            // 这就是数据代理,obj2成为了obj的代理对象
            Object.defineProperty(obj2,'x',{
                get(){
                    return obj.x
                },
                set(value){
                    obj.x = value
                }
            })
        </script>
    </body>
</html>

事件处理

事件的基本使用:

  • 1.使用v-on:xxx 或 @xxx 绑定事件 ,其中xxx是事件名
  • 2.事件的回调需要配置在 methods 对象中,最终会在vm上
  • 3.methods 中配置的函数 ,不要用箭头函数! 否则this就不是vm了
  • 4.methods 中配置的函数 ,都是被Vue所管理的对象,this的指向是vm 或 组件实例对象
  • 5.@click=”demo” 和 @click=”demo($event)” 效果一致,但后者可以传参

事件修饰符

事件修饰符 作用
prevent 阻止默认事件
stop 阻止冒泡
once 事件只触发一次
capture 使用时间的捕获机制
self 只有event.target是当前元素时才触发事件
passive 事件的默认行为立即执行,无需等待事件回调执行完毕

键盘事件

1.Vue常用按键别名:

按键 别名
回车 enter
删除 delete
退出 esc
空格 space
换行 tab
up
down
left
right
2.Vue中未提供别名的按键,可以使用原始的key值去绑定,但是部分键位要把key值转换为kebab-case(短横线命名),如(CapsLock => caps-lock)
3.系统修饰键(用法特殊):cltr、alt、shift、meta
(1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发
(2).配合keydown使用:正常触发事件
4.Vue.config.keyCodes.自定义键名 = 键码,可以自定义按键别名

计算属性与监视

计算属性(computed)

  • 定义:通过已有属性计算得来
  • 原理:底层借助了Object.defineProperty()方法提供的getter和setter
  • getter函数执行时机:初次读取执行一次 和 当依赖的数据发生改变时会被再次调用
  • 优势:与methods相比内部有缓存机制(复用),效率更高,调试方便
    • 计算属性最终会出现在 vm 上,直接读取即可
    • 如果计算属性要被修改,那必须写set函数去响应修改,在set中将计算属性所依赖的那些data数据进行相应改变

监视属性(watch)

  • 当被监视的属性变化时,回调函数handler自动调用,进行相关操作
  • 监视的属性必须存在,才能进行监视
  • 监视的两种方法
    • new Vue()时传入 watch 配置
    • 通过 vm.$watch 监视(要加引号
配置对象 作用
immediate 初始化时回调函数自动调用一次
deep 深度监视

深度监视

  • Vue自身可以监视对象内部值的改变,但Vue提供的watch默认不可以
  • 在监视对象中配置 deep:true 可以监视对象内部值改变

计算属性与监视的区别

1.computed能完成的功能,watch都可以完成
2.watch可以完成异步操作(如定时器),但computed不行(因为computed要有return返回值,而return不能写在回调函数里)

Vue中的this

1.所有被Vue管理的函数,最好写成普通函数,这样this的指向才是Vue 或 组件实例对象
2.所有不被Vue管理的函数(定时器函数、ajax的回调函数、Promise的回调函数)最好写成箭头函数,这样this的指向才是Vue 或 组件实例对象

绑定CSS样式

1.class样式:

:calss=”xxx” ,xxx可以是字符串,对象,数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<body>
    <div class="demo">
        <div class="basic" :class="style" @click='changeMood'>Vue</div>
    </div>
    <script>
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
        new Vue({
            el: '.demo',
            data: {
                mood: 'happy',
                style: {
                    border: false,
                    text: true,
                    position: true
                }
            },
            methods: {
                changeMood() {
                    const arr = ['happy', 'sad', 'upset']
                    let index = Math.floor(Math.random() * 3)
                    this.mood = arr[index]
                }
            }
        })
    </script>
</body>

2.style样式

:style=”{fontSize:xxx}”,xxx是动态值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div class="demo">
        <div class="basic" :style="styleArr" @click='changeMood'>Vue</div>
    </div>
    <script>
        new Vue({
            el: '.demo',
            data: {
                mood: 'happy',
                styleObj: {
                    fontSize: '40px' //这里对象里的key要用驼峰写法
                },
                styleArr: [{
                    fontSize: '20px'
                }, {
                    backgroundColor: 'orange'
                }]
            }
        })

条件渲染

1.v-if

1
2
3
4
5
6
<ul>
    <li v-if="n===1">html</li>
    <li v-else-if="n===2">css</li>
    <li v-else-if="n===3">javascript</li>
    <li v-else>Vue</li>
</ul>

v-if可以和v-else-if、v-else 一起使用,但要求结构不能打乱
v-if:不展示的DOM元素直接被移除,适用于切换频率较低的场景
2.v-show

1
<div v-show='n===1'>v-show</div>

v-show:不展示的DOM元素不会被移除,仅仅是样式被隐藏,适用于切换频率较高的场景

列表渲染

v-for用于展示列表数据
语法:v-for=”(item,index) of xxx” :key=”yyy”
可遍历:数组,对象,字符串,指定次数

1
2
3
 <li v-for="(item,index) of filPersons" :key="item.id">
    {{item.name}}--{{item.age}}
</li>

key作用与原理

列表过滤

列表排序

Vue监视数据原理

Vue会监视data中所有层级的数据
监测对象中的数据:

  • Vue是通过setter实现的监视,且默认Vue只监视new Vue()时传入的数据
  • Vue 不允许动态添加根级响应式属性
  • 如需给后加的属性做响应式,需要使用如下API:
    • Vue.set(target, propertyName/index, value)
    • vm.$set(target, propertyName/index, value)
      三个参数如下:
      {Object | Array} target
      {string | number} propertyName/index
      {any} value
1
2
3
vm.$set(vm.userProfile, 'age', 27)
vm.$set(app.list, 1, "lemon")

Vue.set()&vm.$set() 不能给vm 或 vm的根数据对象(vm._data)添加属性
监测数组中的数据:

  • Vue2是通过object.defineproperty()来劫持数据,无法直接劫持数组
  • 数组中的每一项是没有自己的get,set的
  • 通过包裹数组更新方法实现,本质上就是做了两件事:
    • 调用原生所对应的数组方法对数组进行更新
    • 重新解析模板,进而更新页面
  • Vue修改数组的方法:
    • push()、pop()、shift()、unshift()、splice()、sort()、reverse() (这些数组方法会对原数组进行改变)
    • Vue.set()&vm.$set()

向其所在的节点中渲染文本内容
与插值语法的区别:v-text会替换掉节点中的内容,而不会

v-html

向指定节点中渲染包含html结构的内容
v-html有安全性问题,在网站上动态渲染任意HTML是非常危险的,容易遭到xss攻击

v-cloak

本质是一个没有值的特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
使用css属性配合v-cloak可以解决网速慢页面展示出的问题

v-once

v-once 所在节点在初次动态渲染后,就视为静态内容了
以后数据的改变不会引起v-once所在结构的更新,可用于性能优化

v-pre

可以跳过所在节点的编译过程
可利用它跳过没有使用指令语法和插值语法的节点,会加快编译

自定义指令

函数式:

  • 函数式指令调用时机:
    • 指令与元素成功绑定时(一上来)
    • 指令所在模板被重新解析时
      参数为(DOM元素,绑定对象)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<body>
    <div class="demo">
        <p>{{n}}</p>
        <h1>放大10倍的值: <span v-big="n"></span></h1>      
        <button @click="n++">n++</button>
    </div>
    <script>
        new Vue({
            el: '.demo',
            data: {
                n: 1
            },
            directives: {
                big(e, binding) {
                    console.log(e, binding)//e是DOM元素,binding是
                    e.innerText = binding.value * 10
                }
            }
        })
    </script>
</body>

对象式:
配置对象中常用的三个回调函数
(1).bind:指令与元素成功绑定时调用
(2).inserted:指令所在元素被插入页面时调用
(3).update:指令所在模板结构被重新解析时调用
总结:

函数式即为对象式的简写
分为全局指令和局部指令 Vue.directive(指令名,回调函数/配置对象)
指令定义时不加v-,但使用时要加v-
自定义指令里的 this 是 window
指令名如果是多个单词,要使用kebab-case命名,不要用camelCase命名

生命周期

Vue 在关键时候调用的一些特殊名称的函数
生命周期函数的名字不可更改,其中的 this 指向是vm 或 组件实例对象
常见的生命周期钩子:
1.mounted:发生ajax请求,启动定时器,绑定自定义事件,订阅消息【初始化操作】
2.beforeDestroy:清除定时器,解绑自定义事件,取消订阅消息【收尾工作】

组件

Vue中使用组件的三大步骤:

  • 1.定义组件(创建组件)
  • 2.注册组件
  • 3.使用组件(写组件标签)
    一、如何定义组件?
  • 使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别:
  • 区别如下:
       - 1.el 不要写 —— 因为最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器
       - data 必须写成函数 —— 避免组件被复用时,数据存在引用关系,防止data中的数据被修改时会引起所有引用该组件的模板里的数据都被修改
    简写方式:const 组件名 = options(配置对象)
    二、如何注册组件?
    1.局部注册:靠new Vue 的时候传入components选项
    2.全局注册:靠Vue.components(‘组件名’,组件)
    三、编写组件标签    
        <组件名></组件名>
        <组件名/>

VueComponent 构造函数

一个重要的内置关系

VueComponent.prototype.proto === Vue.prototype
让组件实例对象(vc)可以访问到 Vue原型对象上的属性,方法

单文件组件

vue 脚手架笔记

脚手架文件结构

 |—— node_modules
 |—— public
 |   |—— favicon.ico: 页签图标
 |   |—— index.html: 主页面
 |—— src
 |   |—— assets: 存放静态资源
 |   |   ㆐—— logo.png
 |   |—— components: 存放组件
 |   |   ㆐—— HelloWorld.vue
 |   |—— App.vue: 汇总所有组件
 |   |—— main.js: 入口文件
 |—— .gitignore: git版本管制忽略的配置
 |—— babel.config.js: babel的配置文件
 |—— package.json: 应用包配置文件
 |—— README.md: 应用描述文件
 |—— package-lock.json: 包版本控制文件

render函数

1
2
3
4
5
6
 new Vue({
    render: h => h(App),
}).$mount('#app')
render(createElement){
    return createElement('html标签','标签里的内容')
}

vue.config.js配置文件

ref属性

  • 1.被用来给元素或子组件注册引用信息(id的替代者)
  • 2.应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
1
2
3
 <h1 v-text="msg" ref="title"></h1>
<button @click="showDom" ref="btn">点我输出ref属性</button>
<SchoolName ref="sch"/>

props配置项

让组件接受外部传过来的数据
一、传递数据

如果是数字传入时要用 :age=””(数据绑定的写法,这样的形式代表将引号中的东西看作一个js表达式来处理)
二、接收数据
1.只接收
props:[‘name’]
2.限制类型
props:{
    name:String
}
3.限制类型、限制必要性、指定默认值
props:{
    name:{
        type:String, //类型
        required:true, //必要性
        default:’jyd’ //默认值
    }
}
props是只读的,若确需修改,那么将props中的内容复制到data中一份,然后去改造data中的数据。

mixin(混入)

可以帮多个组件共用的配置提取成一个混入对象
一、定义混合(在一个新的js文件中)
{
    data(){
    },
    methods(){
    }
}
二、使用混入
(1).全局混入:Vue.mixin(xxx)
(2).局部混入: mixins:[xxx]

插件(plugins)

总结TodoList案例

1.组件化编码流程

  • (1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突
  • (2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:
      - 一个组件在用:放在组件自身即可
      - 一些组件在用:放在他们共同的父组件上(状态提升)
  • (3).实现交互:从绑定事件开始
    2.props适用于:
    (1).父组件==> 子组件 通信
    (1).子组件==> 父组件 通信(要求父先给子一个函数)
    3.使用v-model时要切记: v-model绑定的值不能是props传过来的值,因为props是不可以修改的
    4.props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做

浏览器本地存储

sessionStorage/localStorage 的常用方法和属性:

API 作用
setItem() 保存数据
getItem() 读取数据
removeItem() 删除数据
clear() 清除数据
length 数据长度
注意事项:

localStorage需要手动清除才消失,sessionStorage随着浏览器的关闭而消失
如果getItem(xxx)对应的value获取不到,返回值为null
JSON.parse(null)的结果为null

组件的自定义事件

  1. 一种组件间通信的方式,适用于:子组件 ==> 父组件
  2. 适用场景:A是父组件,B是子组件,B要给A传数据,那么就在A中给B绑定自定义事件(回调函数写在A中 )
  3. 绑定自定义事件:
  4. 触发自定义事件:
  5. 解绑自定义事件:
  6. 组件上也可以绑定原生DOM事件,需要使用native修饰符
  7. 注意,通过 this.$refs.std.$on('jyd',callback) 绑定自定义事件时,回调函数要么配置在methos中,要么使用箭头函数,否则this指向会出问题

全局事件总线

  • 一种组件间通信的方式,适用于任意组件通信
  • 全局事件总线是一个独立存在的部分,要想实现组件间的相互通信,又是自定义事件,那就要满足两个条件
      - 满足所有组件都能访问得到全局事件总线
      - 可以调用 $on ,和 $off 和 $emit
    一、实现全局事件总线
    main.js:
1
2
3
4
5
6
7
8
new Vue({
    el:'#app',
    render: h =>h (App)
    //beforeCreate中模板未解析,且this是vm
    beforeCreate(){
        Vue.prototype.$bus = this //安装全局事件总线
    }
})

二、绑定全局事件总线

谁要接收数据,自定义事件就绑定在谁身上

1
2
3
mounted() {
    this.$bus.$on('自定义事件名',callback)
},

三、触发全局事件总线

谁要传递数据,谁就触发事件

1
2
3
4
5
methods:{
    触发事件方法名(){
        this.$bus.$emit('自定义事件名',传递参数)
    }
}

四、在销毁前解绑事件,提高性能

1
2
3
4
// 销毁对应自定义事件
beforeDestroy(){
  this.$bus.$off('自定义事件名')
}

消息订阅与发布

$nextTick

1.语法: this.$nextTick(callback)
2.作用: 在下一次DOM更新结束后执行其回调函数
3.例子:使得input框在创建的时候自动获得焦点

过渡和动画

Vue配置跨域

插槽

Vuex

1.概念
在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信
2.作用
多个组件需要共享数据时
3.搭建vuex环境
4.流程
流程图
5.getter(类似于计算属性)

用于将state中的数据加工
注意要使用其前要先在 new Vuex.Store 中添加

1
2
3
4
5
const getters = {
    bigSum(state) {
        return state.sum * 10
    }
}

6.mapState & mapGetters

写在计算属性里,用于简便快速生成计算属性的
使用前要在组件中先引用 (import {mapState} from 'vuex')
key-value形式:key指的是模板中的写法,value指的是store中的写法

1
2
3
4
5
6
7
8
9
10
11
computed:{
    //传统写法
    /*sum(){
        return this.$store.state.sum
    }*/
    //对象写法
   
    ...mapState({sum:'sum'})
    //数组写法
    ...mapState(['sum'])
}

7.mapActions & mapMutations

mapActions 用于生成于actions对话的方法
mapMutations用于生成于mutations对话的方法
8.namespace

route路由

vue-router:vue的一个插件库,专门实现SPA(单页)应用
一、对SPA的理解:
1.整个应用只有一个完整的页面
2.点击页面中的导航链接不会刷新页面,只会做页面的局部更新
3.数据需要通过AJAX请求获取
二、路由的理解:
1.一个路由就是一组 key-value 的映射关系
2.key 为路径,value 可能是component(前端,用于展示页面内容)/ function(后端,用于处理客户端请求)
三、路由的注意点:
1.路由组件通常存放在pages文件夹,一般组件通常放在components文件夹
2.通过切换,”隐藏”了的路由组件,默认是被销毁的,需要的时候再去挂载
3.每个组件都有自己的 $route 属性,里面存储着自己的路由信息
4.整个应用只有一个router,可以通过组件的 $router属性获取
四、路由在模板中的使用:
路由的组件名 :路由的跳装链接
:路由在模板中的位置

多级路由

在父路由中使用children配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
export default new VueRouter({
    routes: [{
            path: '/subject',
            component: Subject
        },
        {
            path: '/students',
            component: Students,
            children: [{ //在路由中通过children配置子路由
                    path: 'lb', //此处一定不要加'/'
                    component: Lb
                },
                {
                    path: 'jyd', //此处一定不要加'/'
                    component: 'Jyd'
                }
            ]
        }
    ]
})

命名路由

作用:简化路由的跳转路径
1.给路由命名

1
2
3
4
5
{
    name:'hello',
    path:'/students'
    component: Students
}

2.简化跳转

1
2
3
 <router-link to="/students"></router-link>
 ==>
 <router-link :to="{name:'hello'}"></router-link> (此时这里面不要再写path)

路由的 query 参数

1.传递参数
to 要加 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<ul>
      <li v-for="item in p">
        <router-link :to="`/students/lb/msg?id=${item.id}&title=${item.title}`">
          {{ item.title }}
        </router-link>
        <!-- 对象写法 -->
        <!-- <router-link
        :to="{
            path:'/students/lb/msg'
            query:{
              id:item.id
              title:item.title
            }
        }">
        {{item.title}}
        </router-link> -->
      </li>

2.接收参数

$route.query.属性

路由的params参数

1.配置路由声明接收参数

1
2
3
4
{
    path:'/students/:id/:title', //使用占位符  
    component: Students,
}

2.传递参数

1
2
3
4
5
6
7
8
9
10
11
 <router-link to="/students/666/你好"></router-link>
 //对象写法
 <router-link
 :to="{
    name:'hello' //当使用的是params参数时,对象写法里只能写成name属性,不能使用path
    params:{
        id:666,
        title:'你好'
    }
 }">
 </router-link>

路由的props配置

让路由组件更方便的收到参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
    name:'hello',
    path:'/students/:id/:title',  
    component: Students,
    //第一种写法(不常用):会把对象中的每一组key-value值通过props传给组件
    props:{a:900}
    //第二种写法:props为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给组件
    //(只有params能用)
    props:true
    //第三种写法:props为函数,会把函数返回的对象中的每一组key-value值通过props传给组件
    props(route){
        return {
            id:route.query.id,
            title:route.query.title
        }
    }
}

replace属性

作用:控制路由跳转时操作浏览器历史记录的模式
历史记录有push和replace两种写入方式,push是追加(默认),replace是替换当前记录
如何开启replace模式:

1
<router-link replace to="/students"></router-link>

编程式路由导航

缓存路由组件

作用:让不展示的路由组件保持挂载,不被销毁

1
2
3
4
//如果有多个——  :include='['组件名','']'
<keep-alive include='组件名'>
    <router-view></router-view>
</keep-alive>

这段代码写在不想被销毁的组件的父路由上

路由中的生命周期钩子

作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态
1.activated:路由组件激活时触发
2.deactivated:路由组件失活时触发

路由守卫

hash & history


Vue
https://cs-lb.github.io/2024/04/22/开发知识/Vue/
作者
Liu Bo
发布于
2024年4月22日
许可协议