Vue
Vue基本使用
<div id="app">
<div>{{msg}}</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: 'hello world'
}
})
</script>
Vue模板语法
指令
指令的本质就是自定义属性,指令格式 v- 开始,如(v-cloak)
插值表达式存在的问题: “闪动”如何解决该问题:
使用 v-cloak 指令 解决该问题的原理∶先隐藏,替换好值之后再显示最终的值
<style>
[v-cloak] {
display: none;
}
</style>
<div id="app" v-cloak>
<div>{{msg}}</div>
</div>
数据绑定指令
<div id="app" v-cloak>
<!-- 插值表达式 -->
<div v-text='msg'></div>
<!-- 插值表达式,html -->
<div v-html='msg2'></div>
<!-- 打印原始信息 -->
<div v-pre>{{原始信息}}</div>
</div>
数据响应式:数据的响应式(数据的变化导致页面内容的变化)
<!-- v-once 显示内容之后不再具有响应式功能-->
<div v-once>{{info}}</div>
双向数据绑定
<!-- v-model 双向绑定 -->
<input type="text" v-model="msg">
MVVM设计思想:M(model)、V(view)、VM(View-Model)
事件绑定
<button v-on:click='handle'>按钮1</button>
<button @click='handle'>按钮2</button>
<button @click='handle()'>按钮2</button>
var vm = new Vue({
el: '#app',
data: {
num: 0
},
methods: {
handle: function () {
this.num++
}
}
})
事件函数参数传递:
<!-- 直接绑定函数名,默认传递事件对象作为参数 -->
<button @click='handle'>按钮2</button>
<!-- 带参数的函数调用,不传参则为 undefined,$event为固定写法,作为事件对象,且必须写在最后面 -->
<button @click='handle(param, $event)'>按钮2</button>
事件修饰符:
<!-- 阻止事件冒泡 -->
<button v-on:click.stop>按钮1</button>
<button @click.stop>按钮1</button>
<!-- 阻止默认行为 -->
<a href="https://www.baidu.com" @click.prevent>百度</a>
自定义按键修饰符:
<input type="text" @keyup.f1="handle3"> 按下a键才触发
Vue.config.keyCodes.f1 = 65
属性绑定
<a v-bind:href="url">淘宝</a>
<!-- 简写 -->
<a :href="url2"></a>
v-model 原理
<input type="text" v-model="msg">
<input type="text" v-bind:value="msg" v-on:input='msg=$event.target.value'>
样式绑定
class 样式处理:
对象语法:绑定了类名,并且通过数据来切换类名是否可用
<div v-bind:class='{active: isActive}'>
new Vue({
el: '#app',
data: {
isActive: true
},
methods: {
f1: function () {
this.isActive = !this.isActive
}
}
})
数组语法:数组里放类名的变量名,在 vue 模型的数据中修改值
<div v-bind:class='[activeClass]'></div>
new Vue({
el: '#app',
data: {
activeClass: 'active'
},
methods: {
f1: function () {
this.activeClass = ''
}
}
})
<!-- 可以混着使用 -->
<div v-bind:class='[activeClass, {error: isError}]'></div>
对象语法简写
<!-- 对象语法,将数据写在vue中 -->
<div v-bind:class='objClasses'></div>
data: {
objClasses: {
active: true,
error: true
}
}
数组语法简写
<div :class='arrClasses'></div>
data: {
arrClasses: ['active', 'error']
}
原先拥有的 class 属性会保留下来。
style 样式处理
<div :style="{height: heightStyle, width: widthStyle, border: borderStyle}"></div>
data: {
heightStyle: '100px',
widthStyle: '100px',
borderStyle: '1px solid red'
}
简化
<div :style="objStyles"></div>
data{
objStyles: {
height: '100px',
width: '100px',
border: '1px solid green'
}
}
数组用法,写多个
<div :style="[baseStyles, overridingStyles]"></div>
分支循环结构
if 分支
<div v-if='score>90'>优秀</div>
<div v-else-if='score<=90&&score>=80'>良好</div>
<div v-else-if='score<80&&score>60'>良好</div>
<div v-else>比较差</div>
<div></div>
<div v-show="flag">1222222</div>
v-if 控制是否渲染到页面上,v-show 控制是否显示(已经渲染)
for 循环遍历数组
<li v-for="item in fruits">{{item}}</li>
<!-- key能帮助vue区分不同的元素,从而提高性能 -->
<li v-for="(item, index) in fruits" :key="index">{{item}}</li>
for 遍历对象
<div v-for='(value, key, index) in object'></div>
<!-- v-if和v-for结合 -->
<div v-if='value==12' v-for='(value, key, index) in object'></div>
Vue常用特性
表单操作
利用 v-model 绑定数据
表单域修饰符:
- number:转换为数值
- trim:去空格
- lazy:将input事件切换为change事件(change,失去焦点时改变值)
vue的自定义指令
<div id="app">
<input type="text" v-focus>
</div>
Vue.directive('focus', {
inserted: function (el) {
el.focus();
}
})
带参数的自定义指令
<div id="app">
<input type="text" v-color="color">
</div>
// 通过 binding 获取到自定义指令绑定的值
Vue.directive('color', {
// 现阶段与 bind 差不多
inserted: function (el, binding) {
el.style.backgroundColor = binding.value
}
})
new Vue({
el: "#app",
data: {
color: 'green'
}
})
局部指令
new Vue({
el: "#app",
data: {
color: 'green'
},
directives: {
color: {
bind: function (el, binding) {
el.style.backgroundColor = binding.value
}
}
}
})
计算属性
<div id="app">
<div>{{reverseString}}</div>
</div>
new Vue({
el: '#app',
data: {
msg: 'hello'
},
// 计算属性
computed: {
reverseString: function () {
return this.msg.split('').reverse().join('')
}
}
})
计算属性基于它们的依赖进行缓存的,而方法不存在缓存
监听器
应用场景:数据变化时执行异步或开销较大的操作
<div id="app">
<input type="text" v-model='firstName'>
<input type="text" v-model='lastName'>
<div>{{fullName}}</div>
</div>
new Vue({
el: '#app',
data: {
firstName: 'Lisa',
lastName: 'Green',
fullName: 'Lisa Green'
},
watch: {
// 监听了上面两个值的变化
firstName: function (val) {
this.fullName = val + ' ' + this.lastName;
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val;
}
}
})
过滤器
Vue.filter('过滤器名称', function(value) {
// 过滤业务逻辑
})
使用
<div>{{msg | upper}}</div>
<div v-bind:id="id | formatId"></div>
局部定义同上
可以带参数
Vue.filter('过滤器名称', function(value, arg) {
// 过滤业务逻辑
})
使用
<div>{{msg | upper('abc')}}</div>
生命周期
- 挂载(初始化相关属性)
- beforeCreate beforeCreate在实例初始化之后,数据观测和事件配置之前被调用。
- created created在实例创建完成后被立即调用。
- beforeMount beforeMount在挂载开始之前被调用。
- mounted mounted el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。
- 更新(元素或组件的变更操作)
- beforeUpdate beforeUpdate数据更新时调用,发生在虚拟DOM打补丁之前。
- updated updated由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。
- 销毁(销毁相关属性)
- beforeDestroy beforeDestoy实例销毁之前调用。
- detroyed destroyed实例销毁后调用。
综合案例里的几个注意点
// 箭头函数从上下文获取this对象
this.books.some((item) => {
if (item.id == this.id) {
item.name = this.name;
return true;
}
})
常用特性应用场景:
- 过滤器(格式化日期)
- 自定义指令(获取表单焦点)
- 计算属性(统计图书数量)
- 监听器(验证图书存在性)
- 生命周期(图书数据处理)
Vue 组件化开发
组件注册
// 组件注册
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button @click="count++">{{count}}</button>',
// 常规方式,用方法名绑定
methods: {
add: function () {
this.count += 2;
}
}
})
注意事项:
-
data 必须是一个函数
-
组件模板内容必须是单个根元素
-
组件模板内容可以是模板字符串
-
如果使用驼峰式命名组件,那么只能在字符串模板中使用。如果是在普通的标签模板中使用时,必须使用短横线的方式。
template: `
<div>
<button @click="add">{{count}}</button>
<HelloWorld></HelloWorld>
</div>
`
<button-counter></button-counter>
<hello-world></hello-world>
注册局部组件
let componentA = {
data: function() {
return {
msg: 'hello'
}
},
template: `
<div>{{msg}}</div>
`
}
let componentB = {
data: function() {
return {
msg: 'hello'
}
},
template: '<div>{{msg}}</div>'
}
new Vue({
el: '#app',
// 被注册过的局部组件只能在注册他的父组件中使用
components: {
'component-a': componentA,
'component-b': componentB
}
})
组件间数据交互
父组件向子组件传值
<div id="app">
<menu-item title="父组件传递值"></menu-item>
<menu-item :title="ptitle"></menu-item>
</div>
Vue.component('menu-item', {
props: ['title', 'ptitle'],
data: function () {
return {
msg: '子组件数据'
}
},
template: '<div>{{msg + "-----" + title}}</div>'
})
new Vue({
el: '#app',
data: {
ptitle: '父组件传递值'
},
})
props 属性名规则
- 在 props 中使用驼峰形式,模板中则需要使用短横线形式
- 字符串形式的模板中没有这个限制
props 属性值类型
- 字符串 String
- 数值 Number
- 布尔值 Boolean
- 数组 Array
- 对象 Object
<menu-item title="父组件传递值" :num="12" :bool="true" :arr="parr" :obj="pobj"></menu-item>
要用冒号,不然当字符串解析了
子组件向父组件传值
子组件自定义事件,点击事件触发时触发自定义事件告知父组件
<button @click="$emit('enlarge-text')">扩大字体</button>
父组件监听事件,并进行函数处理
<menu-item @enlarge-text="enlarge"></menu-item>
带参数的传递
子组件定义,并传值
<button @click="$emit('enlarge-text', 10)">扩大字体</button>
父组件接收,并带给函数来调用
<menu-item @enlarge-text="enlarge($event)"></menu-item>
非父子组件间传值
通过事件中心来传递
// 创建事件中心
let hub = new Vue();
// 注册当前组件事件
mounted: function () {
hub.$on('tom-event', (val) => {
this.num += val;
})
}
// 定义触发兄弟组件的事件
handle: function() {
hub.$emit('jerry-event', 2)
}
// 销毁事件
hub.$off('tom-event')
hub.$off('jerry-event')
组件插槽
自定义组件里直接插值
<div id="app">
<alert-box>错误信息</alert-box>
</div>
Vue.component('alert-box', {
template: `
<div>
<strong>ERROR:</strong>
<slot></slot>
</div>
`
})
具名插槽
Vue.component('alert-box', {
template: `
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
`
})
// 插槽的使用,slot属性指定哪个具名插槽
<div id="app">
<alert-box>
<h1 slot="header">标题内容</h1>
<p>主要内容</p>
<p slot="footer">底部内容</p>
</alert-box>
</div>
// 使用 template 一个插槽里插多个标签
<alert-box>
<template slot="header">
<h1>标题内容</h1>
<h1>标题内容</h1>
</template>
<p>内容</p>
<template slot="footer">
<h1>标题内容</h1>
<h1>标题内容</h1>
</template>
</alert-box>
作用域插槽
应用场景:父组件对子组件的内容进行加工处理
// 子组件中固定好了模板
<div>
<li v-for="value in list" :key="value.id">
<slot :info="value">{{value.name}}</slot>
</li>
</div>
// 父组件对子组件进行相应的内容处理
<fruit-list :list="list">
<template slot-scope="slotProps">
<strong v-if="slotProps.info.id==2" class="current">{{slotProps.info.name}}</strong>
<strong v-else>{{slotProps.info.name}}</strong>
</template>
</fruit-list>
Vue 前后端交互
Promise 用法
promise 是异步编程的一种解决方案,从语法上讲,Promise 是一个对象,从它可以获取异步操作的消息。
使用 promise 的好处:
- 可以避免多层异步调用嵌套问题(回调地狱)
- Promise 对象提供简洁的API,使得控制异步操作更加容易
// 异步任务创建
let p = new Promise(function (resolve, reject) {
setTimeout(function () {
let flag = false;
if (flag) {
resolve('data');
} else {
reject('error');
}
}, 100);
});
// 两个参数分别为 成功 与 失败 的回调函数
p.then(function (data) {
console.log(data)
}, function (errorData) {
console.log(errorData)
})
// ...... 后续追加代码,实现顺序调用
多次异步调用 ajax 查询
querryData('http://localhost:3000/data')
.then(function (data) {
console.log(data);
return querryData('http://localhost:3000/data1');
}).then(function (data) {
console.log(data);
return querryData('http://localhost:3000/data2');
}).then(function (data) {
console.log(data);
});
then 函数返回值问题
querryData('http://localhost:3000/data')
.then(function() {
return 'hello'
// 调 then 的对象是新创建的默认 promise 对象
}).then(function(data) {
console.log(data)
})
Promise 常用 api
foo().then(function (data) {
console.log(data)
// catch 捕获异常,同上文中的 then 带两个参数
}).catch(function (data) {
console.log(data)
}).finally(function (data) {
console.log(data)
})
// 全部执行完毕,才能接着执行
Promise.all([p1, p2, p3]).then(value => {
console.log(value)
})
// 只有有一个执行完,就执行
Promise.race([p1, p2, p3]).then(value => {
console.log(value)
})
接口调用 fetch 用法
- 更加简单数据获取方式,功能更强大、更灵活,可以看做 xhr 的升级版。
- 基于 promise 实现
fetch('http://localhost').then(function (data) {
// text() 属于 fetch 的方法,返回一个 promise 实例对象,用于获取后台返回的数据
return data.text();
}).then(function (data) {
console.log(data)
})
get 请求等
fetch('http://localhost', {
method: 'get'
}).then(function (data) {
// text() 属于 fetch 的方法,返回一个 promise 实例对象,用于获取后台返回的数据
return data.text();
}).then(function (data) {
console.log(data)
})
带参数的请求
fetch('http://localhost', {
method: 'post',
body: 'uname=lis&pwd=123',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(function (data) {
// text() 属于 fetch 的方法,返回一个 promise 实例对象,用于获取后台返回的数据
return data.text();
}).then(function (data) {
console.log(data)
})
fetch('http://localhost', {
method: 'post',
body: JSON.stringify({
name: 'lis',
age: 12
}),
headers: {
'Content-Type': 'application/json'
}
}).then(function (data) {
// text() 属于 fetch 的方法,返回一个 promise 实例对象,用于获取后台返回的数据
return data.text();
}).then(function (data) {
console.log(data)
})
put 修改
fetch('http://localhost/books/112', {
method: 'put',
body: JSON.stringify({
name: 'lis',
age: 12
}),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(function (data) {
// text() 属于 fetch 的方法,返回一个 promise 实例对象,用于获取后台返回的数据
return data.text();
}).then(function (data) {
console.log(data)
})
// 接收数据,进行修改等操作
app.put('/books/:id', (req, res) => {
res.send();
})
fetch 响应结果
fetch('http://localhost/json').then(function(data) {
return data.json();
}).then(function(data) {
console.log(data.uname)
})
接口调用 -axios 用法
接口调用 -async/await 用法
基于接口的案例
前端工程化
模块化的规范
统一的 es6 模块化规范,是服务器端与浏览器端通用的模块化开发规范。
- 每个 js 文件都是一个独立的模块。
- 导入模块成员使用 import 关键字。
- 暴露模块成员使用 export 关键字。
babel 的安装
webpack 用法
// 该 obj 拥有相应的方法,属性等
import obj from './xx/js'
按需导入
export let s1 = 'aaa'
export let s2 = 'ccc'
export function say = function(){}
import {s1, s2 as ss2, say} from './m1.js'
console.log(s1) // aaa
console.log(ss2) // ccc
console.log(say) //[Function: say]
导入时只需要执行时
import './m2.js'
配置打包的入口与出口
- 入口文件: src -> index.js
- 输出文件:dist -> main.js
Vue 单文件组件
组成结构
- template 组件的模板区域
- script 业务逻辑区域
- style 样式区域
Vue 脚手架
Element-UI 的基本使用