Vue 学习


Vue 学习

目标

  • 基本用法
  • 模板语法
  • 常用特性
  • 实现案例效果

概述

官网:https://cn.vuejs.org/

Vue:渐进式 JavaScript 框架

易用、灵活、高效

MVVM

基本使用

BdWPIA.png

BdWCad.png

插值表达式({{}})

模板语法

前端渲染:把数据填充到 HTML 标签中

渲染方式:原生 js 拼接字符串(将数据以字符串的方式拼接到 HTML 标签中)、使用前端模板引擎(基于模板引擎 art-template,拥有自己的一套模板语法规则)、使用 vue 特有的模板语法

指令

指令的本质就是自定义属性

指令的格式:以 v- 开始(比如:v-cloak)(style 里加)

插值表达式存在的问题:”闪动“

原理:先隐藏,替换好值之后再显示最终的值


必须通过变量添加

v-text 填充纯文本

v-html 填充 HTML 片段(本网站内部数据可以使用,来自第三方的数据不可以用)

v-pre 填充原始信息(显示原始信息,跳过编译过程)

数据响应式

响应式: HTML5 中的响应式(屏幕尺寸的变化导致样式的变化),数据的响应式(数据的变化导致页面内容的变化)

数据绑定:将数据填充到标签中

v-once:只编译一次,显示内容之后不再具有响应式功能,如果显示的信息后续不需要再修改,可以用

双向数据绑定:交互 v-model

事件绑定

v-on

<div>
	<div>{{num}}</div>
	<button v-on:click='num++'>点击</button>
	<button @click='num++'>++</button><!-- 简写 -->
</div>
在 js 中设置 num 值
<div>
	<div>{{num}}</div>
	<button v-on:click='num++'>加</button>
	<button @click='num++'>++</button><!-- 简写 -->
	<button @click='handle'>+</button>
	<button @click='handle()'>自加</button>
</div>

js
let vm = new Vue({
			data: {
				num: 0
			},// 数据
			methods: {
				handle: function () {
					// this 是 vue 的实例对象
					this.num++
				}
			}
})

如果事件直接绑定函数名称,那么会传递事件对象作为事件函数的第一个参数

如果事件绑定函数调用,那么事件对象必须作为最后一个参数显示传递,并且事件对象的名称必须是 $event

.stop 阻止冒泡

.prevent 阻止默认行为(如 a 标签的跳转)

顺序很重要

.enter 回车键

.delete 删除键

自定义按键修饰符:自定义名字,对应的值必须是按键对应的 event.keyCode

v-bind

<a v-bind:hrf='url'>百度</a>
<a :href='url'>百度一下</a><!-- 简写 -->

在 js 中定义 url 的值

Class 与 Style 绑定

样式绑定

<div v-bind:class='{active:isActive, error:isError}'></div>
<div v-bind:class='[activeClass,errorClass]'></div>

对象绑定和数组绑定可以结合使用、class 绑定的值可以简化操作、默认的 class 会保留

<div v-bind:style='{border:borderStyle.width:widthStyle,height:heightStyle}'></div>
<div v-bind:style='[overrideStyle,objStyles]'></div>

条件渲染

分支结构

v-ifv-elsev-else-ifv-show

v-if 控制元素是否渲染到页面

v-show 控制元素是否显示(已经渲染到了页面)

循环结构

v-for

<ul>
	<li :key='index' v-for='(item,index) in list'>{{item}}</li>
</ul>

在 js 中定义 list 数组

常用特性

表单操作

input 单行文本

textarea 多行文本

select 下拉多选

radio 单选框

checkox 多选框

修饰符

.lazy.number.trim

自定义指令

定义是不用加 v-,使用时需要加

钩子函数

钩子函数参数

侦听器

应用场景:数据变化时执行异步或开销较大的操作

过滤器

作用:格式化数据,比如将字符串格式化为首字母大写,将日期格式化为指定的格式等

格式化日期

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>过滤器</title>
</head>

<body>
    <div id="app">
    	<div>{{date|format('yyyy-MM-dd hh:mm:ss')}}</div>
    </div>

    <script src="vue.js"></script>
    <script>
        // 格式化日期
        Vue.filter('format', function (value, arg) {
            function dateFormat(date, format) {
                if (typeof date === 'string') {
                    let mts = date.match(/(\/Date\((\d+)\)\/)/)
                    if (mts && mts.length >= 3) {
                        date = parseInt(mts[2])
                    }
                }
                date = new Date(date)
                if (!date || date.toUTCString() == 'Invalid Date') {
                    return ''
                }
                let map = {
                    'M': date.getMonth() + 1,// 月份
                    'd': date.getDate(),// 日
                    'h': date.getHours(),// 小时
                    'm': date.getMinutes(),// 分
                    's': date.getSeconds(),// 秒
                    'q': Math.floor((date.getMonth() + 3) / 3),// 季度
                    'S': date.getMilliseconds()// 毫秒
                }

                format = format.replace(/([yMdhmsqS])+/g, function (all, t) {
                    let v = map[t]
                    if (v !== undefined) {
                        if (all.length > 1) {
                            v = '0' + v
                            v = v.substr(v.length - 2)
                        }
                        return v
                    } else if (t === 'y') {
                        return (date.getFullYear() + '').substr(4 - all.length)
                    }
                    return all
                })
                return format
            }
            return dateFormat(value, arg)
        })

        let vm = new Vue({
            el: '#app',
            data: {
                date: new Date()
            }
        })
    </script>
</body>

</html>

生命周期

挂载(初始化相关属性)

  • beforeCreate(说明在 beforeCreate 事件触发时,Vue 刚刚实例化,而此时数据 data 和事件方法 methods还未绑定到 app 对象上)
  • created(说明在create事件触发时,数据data和方法methods绑定到应用对象app上)
  • beforeMount(在渲染页面之前,数据是没有挂载的,根据数据生成的DOM对象是获取不到的)
  • mounted(在渲染页面之后,数据是已经挂载的,可以获取数据生成的DOM对象)

更新(元素或组件的变更操作)

  • beforeUpdata(在修改数据之前能获取到数据)
  • updated(修改数据之后也能获取到数据)

销毁(摧毁相关属性)

  • beforeDestroy
  • destroyed
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <div>{{msg}}</div>
        <button @click='update'>更新</button>
        <button @click='destroy'>销毁</button>
    </div>

    <script src="vue.js"></script>
    <script>
        let vm = new Vue({
            el: '#app',
            data: {
                msg: '生命周期'
            },
            methods: {
                update: function () {
                    this.msg = 'hh'
                },
                destroy: function () {
                    this.$destroy()
                }
            },
            beforeCreate: function () {
                console.log('beforeCreate')
            },
            created: function () {
                console.log('created')
            },
            beforeMount: function () {
                console.log('beforeMount')
            },
            mounted: function () {
                console.log('mounted')
            },
            beforeUpdate: function () {
                console.log('beforeUpdate')
            },
            updated: function () {
                console.log('updates')
            },
            beforeDestroy: function () {
                console.log('beforeDestroy')
            },
            destroyed: function () {
                console.log('destroyed')
            },

        })
    </script>
</body>

</html>

数组相关

变异方法(修改原有数据):push()pop()shift()unshift()splice()sort()reverse()

替换数组(生成新的数组):filter()concat()slice()

// 响应式
Vue.set(vm.list, 0, 'a')// 修改数组中元素  数组名,索引,修改的值
vm.$set(vm.list, 1, 'b')// 修改数组中元素

组件化开发

组件化开发思想

标准、分治、重用、组合

Web Components 通过创建封装好功能的定制元素规范组件化

组件注册

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
    	<!-- 使用组件 -->
        <button-counter></button-counter>
        <button-counter></button-counter>
        <button-counter></button-counter>
    </div>

    <script src="vue.js"></script>
    <script>
        // 组件注册
        Vue.component('button-counter', {
            data: function () {
                return { count: 0 }
            },
            template: '<button @click="handle">点击了{{count}}次</button>',
            methods: {
                handle: function () {
                    this.count += 1
                }
            }
        })

        let vm = new Vue({
            el: '#app',
            data: {

            },
        })
    </script>
</body>

</html>
  • data 必须是一个函数
  • 组件模板内容必须是单个根元素
  • 组件模板内容可以是模板字符串(``)
  • 如果使用驼峰式命名组件,那么在使用组件的时候,只能在字符串模板中用驼峰的方式使用组件,但是在普通的标签模板中,必须使用短横线的方式使用组件,如命名为MyComponent,使用时my-component

Vue 调试工具

https://github.com/vuejs/vue-devtools

组件间数据交互

父组件向子组件传值

  • 组件内部通过 props 接收传递过来的值
  • 父组件通过属性将值传递给子组件

props 属性命名规则:在 props 中使用驼峰形式,模板中需要使用短横线的形式;字符串形式的模板中没有这个限制

子组件向父组件传值

  • 子组件通过自定义事件向父组件传递信息($emit()
  • 父组件监听子组件的事件

非父子组件间传值

  • 单独的事件中心管理组件间的通道
  • 监听事件与销毁事件
  • 触发事件
let eventHub=new Vue()

eventHub.$on('add-tode', addTode)
eventHub.$off('add-todo')

eventHub.$emit('add-todo',id)

组件插槽

父组件向子组件传递内容

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <my-alert>bug</my-alert>
        <my-alert>undefined</my-alert>
        <my-alert></my-alert>
    </div>

    <script src="vue.js"></script>
    <script>
        // 组件插槽
        Vue.component('my-alert', {
            template: `
                <div>
                    <strong>ERROR:</strong>
                    <slot>默认的</slot>
                </div>
            `
        })

        let vm = new Vue({
            el: '#app',
            data: {
                
            },
        })
    </script>
</body>

</html>

具名插槽

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <base-layout>
            <p slot='header'>title</p>
            <p>1</p>
            <p>2</p>
            <p>3</p>
            <p slot='footer'>bottom</p>
        </base-layout>
    </div>

    <script src="vue.js"></script>
    <script>
        // 具名插槽
        Vue.component('base-layout', {
            template: `
                <div>
                    <header>
                        <slot name='header'></slot>
                    </header>
                    <main>
                        <slot></slot>
                    </main>
                    <footer>
                        <slot name='footer'></slot>
                    </footer>
                </div>
            `
        })

        let vm = new Vue({
            el: '#app',
            data: {
                pstr: 'hh',
            },
        })
    </script>
</body>

</html>

作用域插槽

应用场景:父组件对子组件的内容进行加工处理

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <fruit-list :list='list'>
            <template slot-scope='slotProps'>
                <strong v-if='slotProps.info.id==2' class="current">{{slotProps.info.name}}</strong>
                <span v-else>{{slotProps.info.name}}</span>
            </template>
        </fruit-list>

    </div>

    <script src="vue.js"></script>
    <script>
        // 作用域插槽
        Vue.component('fruit-list', {
            props: ['list'],
            template: `
                <div>
                    <li :key='item.id' v-for='item in list'>
                        <slot :info='item'>{{item.name }}</slot>
                    </li>
                </div>
            `
        })

        let vm = new Vue({
            el: '#app',
            data: {
                pstr: 'hh',
                list: [{ id: 1, name: 'apple' }, { id: 2, name: 'orange' }, { id: 3, name: 'banana' }]
            },
        })
    </script>
</body>

</html>

前后端交互

接口调用方式:原生 ajax,基于 jQuery 的 ajax,fetch,axios

URL 地址格式:传统形式的 URL,Restful 形式的 URL

Promise

Promise 是异步编程的一种解决方案,从语法上讲,Promise 是一个对象,从它可以获取异步操作的消息

then 参数中的函数返回值:

返回 Promise 实例对象;(返回的该实例对象会调用下一个 then)

返回普通值(返回的普通值会直接传递给下一个 then,通过 then 参数中函数的参数接收该值)

实例方法

p.then():得到异步任务的正确结果

p.catch():获取异常信息

p.finally():成功与否都会执行(尚且不是正式标准)

对象方法

Promise.all():并发处理多个异步任务,所有任务都执行完成才能得到结果

Promise.race():并发处理多个异步任务,只要有一个任务完成就能得到结果

fetch

更加简单的数据获取方式,功能更强大、更灵活,可以看做是 xhr 的升级版

基于 Promise 实现

常用配置选项

methods(String)HTTP 请求方法,默认为 GET(GET/POST/PUT/DELDET)

body(String)HTTP 的请求参数

headers(Object)HTTP的请求头,默认为{}

响应数据格式

text() 将返回体处理成字符串类型

json() 返回结果和 JSON.parse(responseText) 一样

axios

axios 是一个基于 Promise 用于浏览器和 node.js 的 HTTP 端

  • 支持浏览器和 node.js
  • 支持 Promise
  • 能拦截请求和响应
  • 自动转换 JSON 数据

常用 API :get(查询数据),post(添加数据),put(修改数据),delete(删除数据)

响应结果的主要属性

  • data 实际响应回来的数据
  • headers 响应头数据
  • status 响应状态码
  • statusText 响应状态信息

axios 拦截器

请求拦截器:在请求发出之前设置一些信息

响应拦截器:在获取数据之前对数据做一些加工处理

async/await

async/await 是 ES7 引入的新语法,可以更加方便的进行异步操作

async 关键字用于函数上(async 函数的返回值是 Promise 实例对象)

await 关键字用于 async 函数当中(await 可以得到异步的结果)

可以处理多个异步请求

前端路由

路由

路由的本质就是对应关系

在开发中,路由分为后端路由和前端路由

后端路由

根据不同的用户 URL 请求,返回不同的内容

本质:URL 请求地址 与服务器资源之间的对应关系

后端路由根据不同的 URL 地址分发不同的资源

SPA

  • 后端渲染(存在性能问题)
  • Ajax 前端渲染(前端渲染提高性能,但是不支持浏览器的前进后退操作)
  • SPA 单页面应用程序:整个网站只有一个页面,内容的变化通过 Ajax 局部更新实现、同时支持浏览器地址栏的前进和后退操作
  • SPA 实现原理之一:基于 URL 地址的 hash(hash 的变化会导致浏览器记录访问历史的变化、但是 hash 的变化不会触发新的 URL 请求)
  • 在实现 SPA 过程中,最核心的技术点就是前端路由
前端路由

根据不同的用户事件,显示不同的页面内容

本质:用户事件与事件处理函数之间的对应关系

前端路由负责事件监听,触发事件后,通过事件函数渲染不同内容

Vue Router

它和 Vue.js 的核心深度集成,可以非常方便的用于 SPA 应用程序的开发

功能:支持 HTML5 历史模式或 hash 模式;支持嵌套路由;支持路由参数;支持编程式路由;支持命名路由

路由重定向:用户在访问地址 A 的时候,强制用户跳转到地址 C,从而展示特定的组件页面

通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向

$route与对应路由形成高度耦合,不够灵活,所以可以使用 props 将组件和路由解构

props 的值为布尔类型

props 的值为对象类型

props 的值为函数类型

命名路由

为了更加方便的表示路由的路径,可以给路由规则起一个别名,即为“命名路由”

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <router-link to='/user/1'>User1</router-link>
        <router-link to='/user/2'>User2</router-link>
        <router-link :to='{name:"user",params:{id:3}}'>User3</router-link>
        <router-link to='/register'>Register</router-link>

        <!-- 路由占位符 -->
        <router-view></router-view>
    </div>

    <script src="vue.js"></script>
    <script src="vue-router.js"></script>
    <script>
        // 路由组件
        const User = {
            props: ['id', 'uname', 'age'],
            template: '<h1>User 组件 --- id:{{$route.params.id}} --- {{id}} --- {{uname}} --- {{age}}</h1>'
        }
        const Register = {
            template: `
            <div>
                <h1>Register 组件</h1>
                <hr>
                <router-link to='/register/tab1'>tab1</router-link>
                <router-link to='/register/tab2'>tab2</router-link>
                

                <!-- 路由占位符 -->
                <router-view></router-view>
            </div>`
        }

        const Tab1 = { template: '<h3>Tab1 子组件</h3>' }
        const Tab2 = { template: '<h3>Tab2 子组件</h3>' }

        // 路由实例对象
        const router = new VueRouter({
            // 路由规则
            routes: [
                // { path: '/', redirect: '/user/:id' },// 路由重定向

                {
                    name: 'user',// 命名路由
                    path: '/user/:id',// 动态路由匹配
                    component: User,
                    // 路由组件传递参数--布尔类型,对象类型,函数类型
                    props: /*true*/ /*{ uname: 'hh', age: 20 }*/ route => ({ uname: 'gg', age: 2, id: route.params.id })
                },
                {
                    // 嵌套路由
                    path: '/register', component: Register, children: [
                        { path: '/register/tab1', component: Tab1 },
                        { path: '/register/tab2', component: Tab2 },
                    ]
                },
            ]
        })

        // vue 实例对象
        const vm = new Vue({
            el: '#app',
            data: {

            },
            // 挂载路由实例对象
            router
        })
    </script>
</body>

</html>

编程式导航

声明式导航:通过点击链接实现导航的方式

编程式导航:通过调用 JavaScript 形式的 API 实现导航的方式

this.$router.push('hash地址')this.$router.go(n)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值