[阶段3 企业开发基础] 10. 前端基础 Vue2/3

相关资源

视频地址

vue2官方文档

0 Vue简介

基本介绍

vue是一套用于构建用户界面的渐进式js框架

vue特点

  1. 采用组件化,提高代码复用率、且让代码更好维护

  2. 声明式编码,无需直接操作DOM,提高开发效率

    在这里插入图片描述

  3. 使用虚拟DOM+优秀的Diff算法,尽可能复用DOM节点

    在这里插入图片描述

    在这里插入图片描述

搭建vue环境

参考官方文档

Vue周边库

  • vue-cli: vue 脚手架
  • vue-resource
  • axios
  • vue-router: 路由
  • vuex: 状态管理
  • element-ui: 基于 vue 的 UI 组件库(PC 端)

Hello小案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>初识vue</title>
    <!--引入vue-->
    <script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<!--准备容器-->
<div id="root">
    <h1>Hello,{{name}}</h1>
</div>
<script type="text/javascript">
    // 创建vue实例
    new Vue({
        el:'#root', // el 用于指定当前vue实例为哪个容器服务,值通常为css选择器字符串
        data:{ // data 用于存储数据,数据供el指定的容器使用
            name:'Cyan'
        }
    })
</script>
</body>
</html>

小结

  • 要让Vue工作,必须创建一个Vue实例,且要传入一个配置对象
  • root容器中的代码依然符合html代码规范,仅混入Vue的语法而已
  • root容器中的代码被称为[Vue模板]
  • Vue实例和容器是一一对应得
  • 真实开发中只有一个Vue实例,并且会配合组件一起使用
  • {{XXX}}中的XXX要写js表达式,且XXX可以自动读取到data中的所有属性;
  • 一旦data中的数据发生改变,那么模板中的用到该数据的地方会自动更新

注意区分:js表达式和js代码(语句)

1.表达式:一个表达式会产生一个值,可以放在需要值的地方

  • a
  • a+b
  • demo(1)
  • x===y ? ‘a’ : ‘b’

2.js代码(语句)

  • if () {}
  • for () {}

1 Vue核心

1.1 模板语法

插值语法

  • 功能:用于解析标签体内容
  • 写法:{{xxx}},xxx是js表达式,qie可以直接读取到data中的所有属性
<!--准备容器-->
<div id="root">
    <h1>插值语法</h1>
    <h1>Hello,{{name}}</h1>
</div>
<script type="text/javascript">
    // 创建vue实例
    new Vue({
        el: '#root', // el 用于指定当前vue实例为哪个容器服务,值通常为css选择器字符串
        data: { // data 用于存储数据,数据供el指定的容器使用
            name: 'Cyan',
            url:'https://www.baidu.com'
        }
    })
</script>

指令语法

  • 功能:用于解析标签(包括:标签属性、标签体内容、绑定事件…)
  • 写法:v-bind:href=“xxx” 或者 简写为 :href=“xxx”,xxx同样要写js表达式,且可以直接读取到data中的所有属性
<!--准备容器-->
<div id="root">
    <h1>指令语法</h1>
    <a v-bind:href="url">点我去百度</a>
    <a :href="url">点我去百度</a>
</div>
<script type="text/javascript">
    // 创建vue实例
    new Vue({
        el: '#root', // el 用于指定当前vue实例为哪个容器服务,值通常为css选择器字符串
        data: { // data 用于存储数据,数据供el指定的容器使用
            name: 'Cyan',
            url:'https://www.baidu.com'
        }
    })
</script>  

1.2 数据绑定

Vue中两种数据绑定方式:

单向数据绑定

  • 语法:-bind:href=“xxx” 或者 简写为 :href=“xxx”
  • 特点:数据只能从data流向页面

双向数据绑定

  • 语法:v-mode:value=“xxx” 或简写为 v-model=“xxx”
  • 特点:数据不仅能从data流向页面,还可以从页面流向data

备注

  • 双向绑定一般都应用在表单元素上(如input、select等)
  • v-model:value,简写为v-model,因为v-model默认收集的是value的
<!--准备容器-->
<div id="root">
    单向数据绑定:<input type="text" v-bind:value="name"><br/>
    双向数据绑定:<input type="text" v-model:value="name"></br>


    <!-- 该代码是错误的,v-model只能应用在表单类元素上 -->
    <h2 v-model:x="name">Hello</h2>
</div>
<script type="text/javascript">
    // 创建vue实例
    new Vue({
        el: '#root', // el 用于指定当前vue实例为哪个容器服务,值通常为css选择器字符串
        data: { // data 用于存储数据,数据供el指定的容器使用
            name: 'Cyan',
            url:'https://www.baidu.com'
        }
    })
</script>

补充:

el的两种写法

第一种:

const v =  new Vue({
    el: '#root', // el 用于指定当前vue实例为哪个容器服务,值通常为css选择器字符串
    data: { // data 用于存储数据,数据供el指定的容器使用
        name: 'Cyan',
        url:'https://www.baidu.com'
    }
});
console.log(v)

第二种:

v.$mount{'#root'}

data两种写法

第一种:

new Vue({
    el: '#root', // el 用于指定当前vue实例为哪个容器服务,值通常为css选择器字符串
    data: { // data 用于存储数据,数据供el指定的容器使用
        name: 'Cyan',
        url:'https://www.baidu.com'
    }
});

第二种:

new Vue({
    el: '#root', // el 用于指定当前vue实例为哪个容器服务,值通常为css选择器字符串
    data:function() {
    return {
        name:'Cyan'
    }
   }
});

总结

  • el两种写法
    • new Vue时配置el属性
    • 先创建Vue实例,随后通过vm.$mount(‘#root’)指定el的值
  • data两种写法
    • 对象式
    • 函数式
    • 使用组件data必须函数式,否则报错
  • 由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this不再是Vue实例

1.3 MVVM 模型

  • M:模型(Model) :对应 data 中的数据
  • V:视图(View) :模板
  • VM:视图模型(ViewModel) : Vue 实例对象

在这里插入图片描述

总结

  • data中所有属性最终出现在vm身上
  • vm身上所有的属性及Vue原型上所有属性,在Vue模板上中都可以直接使用

1.4 数据代理

<script type="text/javascript">
    let person = {
        name:"张三",
        sex:'男',
        age:18
    }

    Object.defineProperty(person, 'age',{
        value:18,
        enumerable:true, // 控制属性是否可以枚举,默认值false
        writable:true, // 控制属性是否可以被修改,默认值false
        configurable:true // 控制属性是否可以被删除,默认值false
    })
</script>

数据代理

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

let obj = {x:100}
let obj2 = {y:200}

Object.defineProperty(obj2,'x',{
    get() {
        return obj.x;
    },
    set(value) {
        obj.x = value;
    }
})

Vue中的数据代理

在这里插入图片描述

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

1.5 事件处理

在这里插入图片描述

1.5.1 绑定监听

<body>
<!--准备容器-->
<div id="root">
    <h2>欢迎来到{{name}}学习</h2>
<!--    <button v-on:click="showInfo">点击我</button>-->
    <button @click="showInfo">点击我</button>
</div>

</body>
<script type="text/javascript">
    const vm = new Vue({
        el:"#root",
        data:{
            name:'Cyan'
        },
        methods:{
            showInfo() {
                // alert('Hello')
                // console.log(this) 此处this时vm
            }
        }

    })
</script>

事件的基本使用

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

1.5.2 事件修饰符

Vue中的事件修饰符

  • .prevent:阻止默认事件(常用)
  • .stop:阻止事件冒泡(常用)
  • .once:事件只触发一次
  • .capture:使用事件的捕获模式
  • .self:只有event.target是当前操作的元素才触发事件
  • .passive:事件的默认行为立即执行,无需等待事件回调执行完毕

1.5.3 按键修饰符

  • keycode : 操作的是某个 keycode 值的键
  • keyName: 操作的某个按键名的键(少部分

Vue中常用按键别名

enter:回车

delete:删除 (捕获“删除”和“退格”键)

esc:退格

tab:换行(必须配合keydown)

up:上

down:下

left:左

right:右

Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转换为kebab-case(短横线命名)

系统修饰键(用法特殊):ctrl、alt、shift、meta(win)

  • 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才能被触发、
  • 配合keydown使用:正常触发事件

Vue.config.keyCodes 自定义键名=键码(定制按键别名)

1.5.4 计算属性

插值语法实现姓名案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>姓名案例-插值语法实现</title>
</head>
<script type="text/javascript" src="js/vue.js"></script>
<body>
<div id="root">
    姓:<input type="text" v-model:value="firstName"><br>
    名:<input type="text" v-model:value="lastName"><br>
    姓名:<span>{{firstName}}-{{lastName}}</span>
</div>
</body>
<script type="text/javascript">
    new Vue ({
        el:'#root',
        data:{
            firstName:'张',
            lastName:'三'
        }
    })
</script>
</html>

methods实现姓名案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>姓名案例-methods实现</title>
</head>
<script type="text/javascript" src="js/vue.js"></script>
<body>
<div id="root">
    姓:<input type="text" v-model:value="firstName"><br>
    名:<input type="text" v-model:value="lastName"><br>
    姓名:<span>{{fullName()}}</span>
</div>
</body>
<script type="text/javascript">
    new Vue ({
        el:'#root',
        data:{
            firstName:'张',
            lastName:'三'
        },
        methods:{
            fullName() {
                return this.firstName+this.lastName;
            }
        }
    })
</script>
</html>

总结

计算属性:

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

1.7 监视属性

监视属性介绍

天气案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>天气案例</title>
    <script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="root">
    <h2>今天天气很{{info}}</h2>
    <button @click="changeWeather">切换天气</button>
</div>
</body>
<script type="text/javascript">
    const vm = new Vue({
        el:'#root',
        data:{
            isHot:true
        },
        computed:{
            info() {
                return this.isHot ? '炎热':'凉爽'
            }
        },
        methods:{
            changeWeather(){
                this.isHot = !this.isHot
            }
        },
        watch:{
            isHot:{
                immediate:true,// 初始化让handler调用
                // 当isHot发生改变时handler调用
                handler(){
                    console.log('isHot is altered')
                }
            }
        }
    })
</script>
</html>

监视属性两种方式

...
 watch:{
            isHot:{
                immediate:true,// 初始化让handler调用
                // 当isHot发生改变时handler调用
                handler(){
                    console.log('isHot is altered')
                }
            }
        }
 vm.$watch('isHot'.{
        immediate:true,// 初始化让handler调用
            // 当isHot发生改变时handler调用
            handler(){
            console.log('isHot is altered')
        }
    })

监视属性watch

  • 当监视的属性变化时回调函数自动调用,进行相关操作
  • 监视的属性必须存在,才能进行监视
  • 监视的两种写法:
    • new Vue时传入watch配置
    • 通过vm.$watch监视
深度监视
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>天气案例</title>
    <script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="root">
    <h2>今天天气很{{info}}</h2>
    <button @click="changeWeather">切换天气</button>
    <h3>a:{{numbers.a}}</h3>
    <button @click="numbers.a++">点我a+1</button>
    <h3>b:{{numbers.b}}</h3>
    <button @click="numbers.b++">点我b+1</button>
</div>
</body>
<script type="text/javascript">
    const vm = new Vue({
        el:'#root',
        data:{
            isHot:true,
            numbers:{
                a:1,
                b:1
            }
        },
        computed:{
            info() {
                return this.isHot ? '炎热':'凉爽'
            }
        },
        methods:{
            changeWeather(){
                this.isHot = !this.isHot
            }
        },
        watch:{
            isHot:{
                // immediate:true,// 初始化让handler调用
                // 当isHot发生改变时handler调用
                handler(){
                    console.log('isHot is altered')
                }
            },
            // 监视多级结构中所有属性的改变
            numbers:{
                deep:true,
                hander(){
                    console.log('numbers altered')
                }
            }
        }
    })
</script>
</html>

深度监视:

  • Vue中的watch默认不监视对象内部值的改变(一层)
  • 配置deep:true可以监视对象内部值的改变(多层)

备注

  • Vue自身可以监测内部值的改变,但Vue提供的watch默认不可以
  • 使用watch时根据数据的具体结构,决定是否采用深度监视

计算属性与监视属性区别

  • computed能完成的功能,watch都可以完成
  • watch能完成的功能,computed不一定能完成

原则

  • 被Vue管理的函数,最好写成普通函数,如此this的指向才是vm或者组件实例对象
  • 所有不被Vue管理的函数(定时器的回调函数,ajax的回调函数等),最好写成箭头函数,这样this的指向才是vm或组件实例对象

1.8 绑定样式

  • 在应用界面中, 某个(些)元素的样式是变化的

  • class/style 绑定就是专门用来实现动态样式效果的技术

class 绑定

  • :class=‘xxx’
  • 表达式是字符串: ‘classA’
  • 表达式是对象: {classA:isA, classB: isB}
  • 表达式是数组: [‘classA’, ‘classB’]

style 绑定

  • :style=“{ color: activeColor, fontSize: fontSize + ‘px’ }”

  • 其中 activeColor/fontSize 是 data 属性

1.9 条件渲染

1.9.1 条件渲染指令

v-if

  • v-if=“表达式”
  • v-else-if=“表达式”
  • v-else=“表达式”

适用于:切换频率较低的场景

特点:不展示的DOM元素直接被移除

注意:v-if可以和v-else-if、v-else一起使用,但要求结构不能被“打断”

v-show

  • v-show=“表达式”
  • 切换频率较高的场景
  • 特点:不展示DOM元素未被移除,仅仅是使用样式隐藏掉
  • 备注:使用v-if时,元素可能无法获取到,而使用v-show一定可以获取到

1.9.2 比较v-if与v-show

  • 如果需要频繁切换v-show较好
  • 当条件不成立时, v-if 的所有子节点不会解析(项目中使用)

1.10 列表渲染

<body>
<div id="root">
    <h2>人员列表</h2>
    <ul>
        <li v-for="p in persons" :key="p.id">
            {{p.name}}-{{p.age}}
        </li>
    </ul>
</div>

<script type="text/javascript">
    new Vue({
        el:'#root',
        data:{
            persons:[
                {id:'001',name:'张三',age:18},
                {id:'002',name:'李赛',age:19},
                {id:'003',name:'王五',age:20}
            ]
        }
    })
</script>
</body>

v-for指令

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

key作用与原理

index作为key的原理

在这里插入图片描述

id作为key的原理

在这里插入图片描述

面试题:ract、vue中的key作用(key的内部原理)

  1. 虚拟DOM中key的作用
    • key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据[新数据]生成[新的虚拟DOM]
    • 随后Vue进行[新虚拟DOM]与[旧虚拟DOM]的差异比较
  2. 对比规则:
    • 旧虚拟DOM中找到了与新虚拟DOM相同key
      • 若虚拟DOM中内容没变,直接使用之前的真实DOM
      • 若虚拟DOM内容改变,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
    • 旧虚拟DOM中未找到与新虚拟DOM相同的key
      • 创建新的真实DOM,随后渲染到页面
  3. 用index作为key可能会引发的问题
    • 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新(界面效果没问题,但效率低)
    • 如果结构中还包含输入类的DOM:会阐述错误DOM更新(界面造成问题)
  4. 开发中如何选择key
    • 最好使用每条数据的唯一标识作为key
    • 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key没有问题

列表过滤

watch实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>基本列表</title>
    <script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="root">
    <h2>人员列表</h2>
    <input type="text" placeholder="请输入名字" v-model="keyword">
    <ul>
        <li v-for="p in filPersons" :key="p.id">
            {{p.name}}-{{p.age}}
        </li>
    </ul>
</div>

<script type="text/javascript">
    // watch实现
    new Vue({
        el:'#root',
        data:{
            keyword:'',
            persons:[
                {id:'001',name:'张三',age:18},
                {id:'002',name:'李赛',age:19},
                {id:'003',name:'王五',age:20},
                {id:'004',name:'老刘',age:22}
            ],
            filPersons:[]
        },
        watch:{
            keyword:{
                immediate:true,
                handler(val) {
                this.persons = this.persons.filter((p)=>{
                    return p.name.indexOf(val) !== -1
                })
            }
        }
    }
</script>
</body>
</html>

computed实现

  new Vue({
        el: '#root',
        data: {
            keyword: '',
            persons: [
                {id: '001', name: '张三', age: 18},
                {id: '002', name: '李赛', age: 19},
                {id: '003', name: '王五', age: 20},
                {id: '004', name: '老刘', age: 22}
            ],
            filPersons: []
        },
        computed: {
            filPersons() {
               return this.persons = this.persons.filter((p) => {
                    return p.name.indexOf(this.keyword) !== -1
                })
            }
        }
    })

列表排序

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>基本列表</title>
    <script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="root">
    <h2>人员列表</h2>
    <input type="text" placeholder="请输入名字" v-model="keyword">
    <button @click="sortedType = 2">年龄升序</button>
    <button @click="sortedType = 1">年龄降序</button>
    <button @click="sortedType = 0">原顺序</button>
    <ul>
        <li v-for="p in filPersons" :key="p.id">
            {{p.name}}-{{p.age}}
        </li>
    </ul>
</div>

<script type="text/javascript">

    new Vue({
        el: '#root',
        sortedType:0, // 0原顺序,1降序 2升序
        data: {
            keyword: '',
            persons: [
                {id: '001', name: '张三', age: 18},
                {id: '002', name: '李赛', age: 19},
                {id: '003', name: '王五', age: 20},
                {id: '004', name: '老刘', age: 22}
            ],
            filPersons: []
        },
        computed: {
            filPersons() {
               const arr =  this.persons = this.persons.filter((p) => {
                    return p.name.indexOf(this.keyword) !== -1
                })
                // 判断是否需要排序
                if(this.sortedType) {
                    arr.sort((p1, p2)=>{
                        return this.sortedType === 1 ? p2.age-p1.age : p1.age - p2.age
                    })
                }
                return arr
            }
        }
    })
</script>
</body>
</html>             

1.11 Vue监测数据

Vue监视数据的原理

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

  2. 如何监测对象中的数据

    通过settser实现监视,且要在new Vue时就传入要监测的数据

    • 对象中后追加的属性,Vue默认不做响应式处理

    • 如需给后添加的属性做响应式,请使用如下API

      Vue.set(target, propertyName/index, value) 
      或
      vm.$set(target, propertyName/index, value)
      
  3. 如何监测数组中的数据

    通过包裹数组更新元素的方法实现,本质就是做了两件事:

    • 调用原生对应的方法对数组进行更新
    • 重新解析模板,进而更新页面
  4. 在Vue修改数组中的某个元素一定要用如下方法:

    1.使用这些API;push()、pop()、shift()、unshift()、splice()、sort()、reverse()
    2.Vue.set()或vm.$set()
    

    特别注意 Vue.set()vm.$set()不能给vm或者vm的根数据对象添加属性

1.12 收集表单数据

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>收集表单数据</title>
    <script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="root">
    <form @submit.prevent="demo">
        账号:<input type="text" v-model="userInfo.account"><br/><br/>
        密码:<input type="password" v-model="userInfo.password"><br/><br/>
        性别:
        男<input type="radio" name="sex" value="male" v-model="userInfo.sex"><input type="radio" name="sex" value="female" v-model="userInfo.sex"><br/><br/>
        爱好:
        学习<input type="checkbox" v-model="userInfo.hobby" value="study">
        打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
        吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
        <br/><br/>
        所属校区:
        <select v-model="userInfo.city">
            <option value="">请选择校区</option>
            <option value="beijing">北京</option>
            <option value="shanghai">上海</option>
            <option value="nantong">南通</option>
            <option value="haerbin">哈尔滨</option>
        </select>
        <br/><br/>
        其他信息:
        <textarea v-model="userInfo.other"></textarea><br/><br/>
        <input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://baidu.com">《用户协议》</a>
        <button>提交</button>
    </form>
</div>
<script>
    new Vue({
        el:'#root',
        data:{
           userInfo:{
               account:'',
               password:'',
               sex:'male',
               hobby:[],
               city:'shanghai',
               other:'',
               agree:''
           }
        },
        methods:{
            demo(){
                console.log(JSON.stringify(this.userInfo))
            }
        }
    })
</script>
</body>
</html>
  • <input type="text"/>,则v-model收集的是value值,用户输入的就是value值
  • <input type="radio"/>,则v-model收集的是value值,且要给标签配置value值
  • <input type="checkbox"/>
    • 没有配置input的value属性,那么收集的就是checked(布尔值)
    • 配置input的value属性
      • v-model的初始值是非数组,那么收集的就是checked(布尔值)
      • v-model的初始值是数组,那么收集的就是value构成的数组
    • 备注 v-model的三个修饰符
      • lazy 失去焦点再加载数据
      • number 输入字符串转为有效数字
      • trim 输入首尾空格过滤

1.13 过滤器

格式化时间案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>过滤器</title>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript" src="js/dayjs.min.js"></script>
</head>
<body>
<div id="root">
    <h2>显示格式化后的时间</h2>
    <!-- 计算属性实现 -->
    <h3>现在是:{{fmtTime}}</h3>
    <!-- methods实现 -->
    <h3>现在是:{{getFmtTime()}}</h3>
    <!-- 过滤器实现 -->
    <h3>现在是:{{time | timeFormater}}</h3>
    <!-- 过滤器实现(传参) -->
    <h3>现在是:{{time | timeFormater('YYY_MM_DD')}}</h3>

</div>
<script type="text/javascript">
    new Vue({
        el:'#root',
        data:{
            time:1621561377603 // 时间戳
        },
        computed:{
            fmtTime(){
                return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
            }
        },
        methods:{
            getFmtTime(){
                return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
            }
        },
        filters:{
            timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
                return dayjs(value).format('YYYY-MM-DD HH:mm:ss')
            }
        }
    })
</script>
</body>
</html>

过滤器

定义 对要显示的数据进行特定格式化后再显示

语法

  • 注册过滤器 Vue.filter(name,callback)new Vue(filters:{})
  • 使用过滤器 {{xxx | 过滤器名}}v-bind:属性="xxx | 过滤器名"

备注

  • 过滤器也可以接受额外参数、多个过滤器可以串联
  • 并没有改变原本的数据,是产生新的对应的数据

1.14 内置指令

指令回顾

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

v-text

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

v-html

  • 作用:向指定节点中渲染包含html结构的内容
  • 与插值语法区别:
    • v-html会替换掉节点所有内容 {{xx}}则不会
    • v-html可以识别html结构
  • 注意 v-html有安全性问题
    • 在网站动态渲染任何HTML是危险的,容易导致XSS攻击
    • 一定要在可信的内容上使用v-html,永不要用在用户提交的内容上

v-cloak(没有值)

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

v-once

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

v-pre

  • 跳过其所在节点的编译过程
  • 可以利用它跳过:没有使用指令语法、没有使用插值语法的节点、会加快编译速度

1.15 自定义指令

定义语法

  • 局部指令

    new Vue({
    	directives:{指令名:配置对象}
    })
    // 或者
    new Vue({
    	directives(){}
    })
    
  • 全局指令

    Vue.directive(指令名, 配置对象)
    // 或者
    Vue.directive(指令名, 回调函数)
    

配置对象中常用的三个回调

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

备注

  • 指令定义时不加v-,但使用时要加v-
  • 指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名

1.16 Vue生命周期

生命周期

  • 别名:生命周期回调函数、生命周期函数、生命周期钩子
  • 概念:Vue关键时刻帮我们调用的一些特殊名称的函数
  • 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
  • 生命周期函数中的this指向是vm或组件实例对象

Vue生命周期

  • 将要创建—>调用beforeCreate函数
  • 创建完毕—>调用created函数
  • 将要挂载—>调用beforeMount函数
  • 挂载完毕—>调用mounted函数 [重要的钩子]
  • 将要更新–>调用beforeUpdate函数
  • 更新完毕—>调用update函数
  • 将要销毁—>调用beforeDestroy函数 [重要的钩子]
  • 销毁完毕—>调用destroyed函数

常用的生命周期钩子

  • mounted 发送ajax请求,启动定时器、绑定自定义事件、订阅消息 等初始化工作
  • beforeDestroy 清除定时器、解绑自定义事件、取消订阅等 收尾工作

关于销毁Vue实例

  • 销毁后借助Vue开发者工具看不到任何信息
  • 销毁后自定义事件会失效,但原生DOM事件依然有效
  • 一般不会在beforeDestroy操作数据,因为即便操作数据,也不会触发更新流程了

2 Vue组件化编程

2.1 模块与组件、模块化与组件化

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

模块

  • 理解:向外提供特定功能的 js 程序, 一般就是一个 js 文件
  • 原因:js文件很多很复杂
  • 作用:复用 js, 简化 js 的编写, 提高 js 运行效率

组件的定义

  • 组件:实现应用中局部功能代码资源集合
  • 原因:界面功能复杂
  • 作用:复用编码, 简化项目编码, 提高运行效率

模块化

当应用中的 js 都以模块来编写的,那这个应用就是一个模块化的应用。

组件化

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

2.2 非单文件组件

定义

一个文件中包含N个组件

注意: 组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务哪个对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>非单文件组件</title>
    <script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="root">
    <!-- 第三步 编写组件标签 -->
    <school></school>
    <hr>
    <student></student>

</div>
</body>
<script type="text/javascript">

    // 第一步 创建school组件
    const school = Vue.extend({
        template:`
            <div>
                <h2>学校名称:{{schoolName}}</h2>
                <h2>学校地址:{{address}}</h2>
                <button @click="showName">点我提示学校名</button>
            </div>
        `,
        data() {
            return {
                schoolName:'上交',
                address:'上海'
            }
        },
        methods:{
            showName() {
                alert(this.schoolName)
            }
        }
    })

    // 第一步 创建student组件
    const student = Vue.extend({
        template:`
            <div>
                <h2>学生姓名:{{studentName}}</h2>
                <h2>学生年龄:{{age}}</h2>
            </div>
        `,
        data() {
            return {
                ageName:'上交',
                age:18
            }
        }
    })

    // 创建vm
    new Vue({
        el:'#root',
        // 第二步 注册组件(局部注册)
        components:{
            school,
            student

        }
    })
</script>
</html>

Vue使用组件的三大步骤

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

如何定义一个组件

使用Vue.extend(options)创建,其中optionsnew Vue(options)时传入的那个options几乎一样,但有点区别

区别

  • el不要写,因为最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器
  • data必须写成函数,因为避免复用组件时,数据存在引用关系
  • 备注 使用template可以配置组件结构

如何注册组件

  • 局部注册:new Vue时传入component选项
  • 全局注册:Vue.component('组件名',组件)

编写组件标签

<school></school>

注意点

  • 关于组件名
    • 一个单词组成
      • 第一种写法(首字母小写)school
      • 第二种写法(首字母大写)School
    • 多个单词组成
      • ·第一种写法(kebab-case命名):my-school
      • 第二种写法(CamelCase命名):MySchool(需要Vue脚手架支持)
    • 备注:
      • 组件吗尽可能回避HTML中已经有的元素名称,如h2H2
      • 可以使用name配置项指定组件在开发者工具中呈现的名字
  • 关于组件标签
    • 第一种写法<school></school>
    • 第二种写法<school/>
    • 备注:不使用脚手架时,<school/>会导致后续组件不能渲染
  • 一个简写方式
    • const school = Vue.extent(options)简写为const school = options

组件的嵌套

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组件的嵌套</title>
    <script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="root">
    <app></app>
</div>

</body>
<script type="text/javascript">

    // 创建student组件
    const student = Vue.extend({
        template:`
            <div>
                <h2>学生姓名:{{name}}</h2>
                <h2>学生年龄:{{age}}</h2>
            </div>
        `,
        data() {
            return {
                name:'Cyan Chau',
                age:18
            }
        }
    })


    // 创建school组件
    const school = Vue.extend({
        template:`
            <div>
                <h2>学校名称:{{schoolName}}</h2>
                <h2>学校地址:{{address}}</h2>
                <student></student>
            </div>
        `,
        data() {
            return {
                schoolName:'上交',
                address:'上海'
            }
        },
        components:{
            student
        }
    })


    // 创建hello组件
    const hello = Vue.extend({
        template:`<h1>{{msg}}</h1>`,
        data() {
            return {
                msg:'欢迎来到我的博客!'
            }
        }
    })

    // 创建app组件
    const app = Vue.extend({
        template:`
        <div>
            <hello></hello>
            <school></school>
        </div>
        `,
        components:{
            school,
            hello
        }
    })

    // 创建vm
    new Vue({
        el:'#root',
        components:{
            app
        }
    })


</script>
</html>

VueComponent

  1. school组件本质是一个名为VueComponent的构造函数,且不是我们定义的,是Vue.extend生成的
  2. 我们只需要写或者。Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行:new VueComponent(options)
  3. 每次调用Vue.extend,返回的都是全新的VueComponent
  4. this指向:
    • 组件配置:data函数、methods中函数、watch中函数、computed中的函数,它们的this均是VueComponent实例对象
    • new Vue()配置:data函数、methods中的函数、watch中的函数、computed中的函数,它们的this均是Vue实例对象
  5. VueComponent的实例对象,简称vc(组件实例对象),Vue的实例对象,简称vm

重要内置关系

在这里插入图片描述

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

2.3 单文件组件

定义

一个文件中只包含1一个组件

样例

<template>
<!-- 组件的结构 -->
</template>

<script>
    // 组件的交互(数据、方法)
</script>

<style>
    /*组件的样式*/
</style>

School.vue

<template>
    <!-- 组件的结构 -->
    <div class="demo">
        <h2>学校名称:{{schoolName}}</h2>
        <h2>学校地址:{{address}}</h2>
        <button @click="showName">点我提示学校名</button>
    </div>
</template>

<script>
    // 组件的交互(数据、方法)
    export default {
        name:'School',
        data(){
            return {
                schoolName:'上交',
                address:'上海'
            }
        },
        methods:{
            showName() {
                alert(this.schoolName)
            }
        }
    }
</script>

<style>
    /*组件的样式*/
    .demo{
        background-color: aquamarine;
    }
</style>

Student.vue

<template>
    <!-- 组件的结构 -->
    <div>
        <h2>学生姓名:{{name}}</h2>
        <h2>学生年龄:{{age}}</h2>
    </div>
</template>

<script>
    // 组件的交互(数据、方法)
    export default {
        name:'Student',
        data(){
            return {
                name:'张三',
                age: 18
            }
        }

    }
</script>

<style>
    /*组件的样式*/

</style>

App.vue

<template>
    <div>
        <School></School>
        <Student></Student>
    </div>
</template>

<script>
    // 引入组件
    import School from './School'
    import Student from './Student'

    export default {
        name: "APP",
        components:{
            School,
            Student
        }
    }
</script>

<style>

</style>

main.js

import App from './App'

new Vue({
    el:'#root',
    template:` <App></App>`,
    components:{
        App
    }
})

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>单文件组件</title>
</head>
<body>
    <div id="root"></div>
    <script type="text/javascript" src="../js/vue.js"></script>
    <script type="text/javascript" src="main.js"></script>
</body>
</html>

3 Vue脚手架

入门

官方文档

1.全局安装@vue/cli

npm install -g @vue/cli

2.切换到要创建项目的目录,使用命令创建目录

vue create xxxx

备注

  1. 出现下载缓慢,配置npm淘宝镜像 npm config set registry https://registry.npm.taobao.org
  2. Vue脚手架隐藏了所有webpack相关的配置,查看具体的配置,执行vue inspect > output.js

关于不同版本的Vue

  1. vue.js与vue.runtime.xxx.js区别
    • vue.js是完整版的Vue,包含核心功能+模板解析器
    • vue.runtime.xxx.js是运行版的Vue,只包含:核心功能(没有模板解析器)
  2. 因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数饥饿收到的createElement函数去指定具体内容

main.js

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

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

ref属性

  1. 被用来给元素或子组件注册引用信息(id的替代者)
  2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
  3. 使用方式
    • 打标识<h1 ref="xxx">...<h1><School ref="xxx"></School>
    • 获取this.$refs.xxx

props配置

功能:让组件接收外部传来的数据

传递数据:<Demo name="xxx"/>

接收数据:

  • 简单接收

    props:['name']
    
  • 限制类型

    props:{name:Number}
    
  • 限制类型、限制必要性、指定默认值

    props:{
        name:{
            type:String, // 类型String
            required:true // 必要性
    		default:'CYAN' // 默认值
        }
    
    }
    

    props是只读的,Vue底层会检测对props的修改,若进行修改,会发出警告,若必须修改,则复印props内容到data中一份,然后修改data中的数据

App.vue

<template>
    <div>
        <Student name="丽萨" sex="女" :age="18"/>
        <Student name="卡拉" sex="男" :age="18"/>
    </div>
</template>

<script>
    // 引入组件
    import School from '../src/components/Student'
    import Student from '../src/components/School'

    export default {
        name: "App",
        components:{
            Student
        }
    }
</script>

<style>

</style>

Student.vue

<template>
    <!-- 组件的结构 -->
    <div>
        <h2>{{msg}}</h2>
        <h2>学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2>
        <h2>学生年龄:{{age}}</h2>
    </div>
</template>

<script>
    // 组件的交互(数据、方法)
    export default {
        name:'Student',
        data(){
            return {
                msg:'我是一个学生'
            }
        },
        // props:['name','sex','age'] 简单接收
        // 接收的同时对数据进行类型限制
        // props:{
        //     name:String,
        //     age:Number,
        //     sex:String
        // }
        // 接收的同时对数据进行类型限制+默认值指定+必要性限制
        props:{
            name:{
                type:String, // 类型String
                required:true // 必要的
            },
            age:{
                type:Number,
                default:99
            },
            sex:{
                type:String, // 类型String
                required:true // 必要的
            }
        }

    }
</script>

<style>
    /*组件的样式*/

</style>

mixin混入

功能:把多个组件共用的配置提取成一个混入对象

使用方式:

第一步,定义混合

{
	data(){...},
	methods:{...},
	...	
}

第二步,使用混入

全局混入:Vue.mixin(xxx)

局部混入:mixins:['xxx']

School.vue

<template>
    <!-- 组件的结构 -->
    <div>
        <h2 @click="showName">学校名称:{{name}}</h2>
        <h2>学校地址:{{address}}</h2>
    </div>
</template>

<script>
    // 引入混合
    import {mix} from '../mixin'
    // 组件的交互(数据、方法)
    export default {
        name:'School',
        data(){
            return {
                name:'上交',
                address:'上海'
            }
        },
        mixins:[mix]

    }
</script>

<style>

</style>

Student.vue

<template>
    <!-- 组件的结构 -->
    <div>
        <h2 @click="showName">学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2>
    </div>
</template>

<script>
    // 引入混合
    import {mix} from '../mixin'
    // 组件的交互(数据、方法)
    export default {
        name:'Student',
        data(){
            return {
                name:'Cyan',
                sex:'female'
            }
        },
        mixins:[mix]
    }
</script>

<style>
    /*组件的样式*/

</style>

mixin.js

export const mix = {
    methods:{
        showName() {
            alert(this.name)
        }
    }
}

插件

功能:用于增强Vue

本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据

定义插件:

对象.install = function (Vue, options) {
    // 添加全局过滤器
    Vue.filter(...)
    
    // 添加全局指令
    Vue.directive(...)
   
    // 配置全局混入
    Vue.mixin(...)
    
    // 添加实例方法
    Vue.prototype.$myMethod = function() {...}
    Vue.prototype.$myProperty = xxx   
}

使用插件

import plugins from './plugins'

Vue.use(plugins)

scoped样式

功能:让样式在局部生效,防止冲突

写法:

<style scoped>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cyan Chau

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值