目录
vue 简介
vue 的特性
数据驱动视图
双向数据绑定
MVVM
vue 的基本使用
vue 的调试工具
vue 的指令
1、内容渲染指令
2、属性绑定指令
3、事件绑定
4、双向绑定指令 v-model
5、 条件渲染指令
6 、列表渲染指令
vue过滤器
定义过滤器基本使用
私有过滤器和全局过滤器
过滤器的注意点
watch 侦听器
使用 watch 检测用户名是否可用
侦听器的格式
对象侦听器
deep 选项
计算属性
计算属性的特点
vue-cli 的使用
安装和使用
vue 项目中 src 目录的构成:
vue 项目的运行流程
vue 组件
vue 组件的三个组成部分
template
script
style
组件之间的父子关系
通过 components 注册的是私有子组件
注册全局组件
组件的 props
组件之间的样式冲突问题
组件的生命周期
组件之间的数据共享
vue 简介
是一套用于构建用户界面的前端框架。
vue 的特性
- 数据驱动视图
- 双向数据绑定
数据驱动视图
vue 会监听数据的变化,从而自动重新渲染页面的结构
双向数据绑定
MVVM
MVVM 是 vue 实现数据驱动视图和双向数据绑定的核心原理。MVVM 指的是 Model、View 和 ViewModel,
vue 的基本使用
基本使用步骤
- 导入 vue.js 的 script 脚本文件
- 在页面中声明一个将要被 vue 所控制的 DOM 区域
- 创建 vm 实例对象(vue 实例对象)
<!-- 希望 Vue 能够控制下面的这个 div,帮我们在把数据填充到 div 内部 --> <div id="app">{{ username }}</div> //视图部分 <!-- 1. 导入 Vue 的库文件,在 window 全局就有了 Vue 这个构造函数 --> <script src="./lib/vue-2.6.12.js"></script> <!-- 2. 创建 Vue 的实例对象 --> <script> // 创建 Vue 的实例对象 const vm = new Vue({ // el 属性是固定的写法,表示当前 vm 实例要控制页面上的哪个区域,接收的值是一个选择器 el: '#app', // data 对象就是要渲染到页面上的数据 data: { username: 'zhangsan' } }) </script>
vue 的调试工具
vue 的指令
指令的概念
指令(Directives)是 vue 为开发者提供的模板语法,用于辅助开发者渲染页面的基本结构。
- 内容渲染指令
- 属性绑定指令
- 事件绑定指令
- 双向绑定指令
- 条件渲染指令
- 列表渲染指令
1、内容渲染指令
- v-text
- {{ }}
- v-html
v-text 语法
<div id="app">
<p v-text="username"></p>
<p v-text="gender">性别:</p>
</div>
{{ }} 语法
<p>姓名:{{ username }}</p>
<p>性别:{{ gender }}</p>
v-html 语法
<div v-html="info"></div>
2、属性绑定指令
注意:插值表达式只能用在元素的内容节点中,不能用在元素的属性节点中!
-
在 vue 中,可以使用
v-bind:
指令,为元素的属性动态绑定值; -
简写是英文的
:
-
在使用 v-bind 属性绑定期间,如果绑定内容需要进行动态拼接,则字符串的外面应该包裹单引号,例如:
<div :title="'box' + index">这是一个 div</div>
3、事件绑定
-
v-on:
简写是@
-
语法格式为:
<button @click="add"></button> methods: { add() { // 如果在方法中要修改 data 中的数据,可以通过 this 访问到 this.count += 1 } }
-
$event
的应用场景:如果默认的事件对象 e 被覆盖了,则可以手动传递一个 $event。例如:<button @click="add(3, $event)"></button> methods: { add(n, e) { // 如果在方法中要修改 data 中的数据,可以通过 this 访问到 this.count += 1 } }
-
事件修饰符:
-
.prevent
阻止默认行为<a @click.prevent="xxx">链接</a>
-
.stop
阻止事件冒泡<button @click.stop="xxx">按钮</button>
-
-
按键修饰符
<div id="app"> <input type="text" @keyup.esc="clearInput" @keyup.enter="commitAjax"> </div>
4、双向绑定指令 v-model
<div id="app">
<p>用户的名字是:{{ username }}</p>
<input type="text" v-model="username">
<hr>
<select v-model="city">
<option value="">请选择城市</option>
<option value="1">北京</option>
<option value="2">上海</option>
<option value="3">广州</option>
</select>
</div>
- input 输入框
- type="radio"
- type="checkbox"
- type="xxxx"
- textarea
- select
语法:
<input type="text" v-model.number="n1"> + <input type="text" v-model.number="n2"> = <span>{{ n1 + n2 }}</span>
5、 条件渲染指令
v-show
的原理是:动态为元素添加或移除display: none
样式,来实现元素的显示和隐藏- 如果要频繁的切换元素的显示状态,用 v-show 性能会更好
v-if
的原理是:每次动态创建或移除元素,实现元素的显示和隐藏- 如果刚进入页面的时候,某些元素默认不需要被展示,而且后期这个元素很可能也不需要被展示出来,此时 v-if 性能更好
在实际开发中,绝大多数情况,不用考虑性能问题,直接使用 v-if 就好了!!!
v-if 指令在使用的时候,有两种方式:
-
直接给定一个布尔值 true 或 false
<p v-if="true">被 v-if 控制的元素</p>
-
给 v-if 提供一个判断条件,根据判断的结果是 true 或 false,来控制元素的显示和隐藏
<p v-if="type === 'A'">良好</p>
6 、列表渲染指令
- list 是待循环的数组
- item 是被循环的每一项
<tr v-for="(item, index) in list" :key="item.id">
<td>{{ index }}</td>
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
</tr>
vue过滤器
定义过滤器基本使用
<div id="app">
<p>message 的值是:{{ message | capi }}</p>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
message: 'hello vue.js'
},
// 过滤器函数,必须被定义到 filters 节点之下
// 过滤器本质上是函数
filters: {
// 注意:过滤器函数形参中的 val,永远都是“管道符”前面的那个值
capi(val) {
// 字符串有 charAt 方法,这个方法接收索引值,表示从字符串中把索引对应的字符,获取出来
// val.charAt(0)
const first = val.charAt(0).toUpperCase()
// 字符串的 slice 方法,可以截取字符串,从指定索引往后截取
const other = val.slice(1)
// 强调:过滤器中,一定要有一个返回值
return first + other
}
}
})
</script>
私有过滤器和全局过滤器
// 使用 Vue.filter() 定义全局过滤器
Vue.filter('capi', function (str) {
const first = str.charAt(0).toUpperCase()
const other = str.slice(1)
return first + other + '~~~'
})
过滤器的注意点
- 要定义到 filters 节点下,本质是一个函数
- 在过滤器函数中,一定要有 return 值
- 在过滤器的形参中,可以获取到“管道符”前面待处理的那个值
- 如果全局过滤器和私有过滤器名字一致,此时按照“就近原则”,调用的是”私有过滤器“
连续调用多个过滤器
过滤器传参
第一个参数已经固定,传参只能在第二个
过滤器仅在 vue 2.x 和 1.x 中受支持,在 vue 3.x 的版本中剔除了过滤器相关的功能。
watch 侦听器
语法格式如下:
<div id="app">
<input type="text" v-model="username">
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
username: 'admin'
},
// 所有的侦听器,都应该被定义到 watch 节点下
watch: {
// 侦听器本质上是一个函数,要监视哪个数据的变化,就把数据名作为方法名即可
// 新值在前,旧值在后
username(newVal,oldVal) {
console.log(neVal,oldVal)
}
}
})
</script>
使用 watch 检测用户名是否可用
语法:
watch: {
// 侦听器本质上是一个函数,要监视哪个数据的变化,就把数据名作为方法名即可
// 新值在前,旧值在后
username(newVal) {
if (newVal === '') return
// 1. 调用 jQuery 中的 Ajax 发起请求,判断 newVal 是否被占用!!!
$.get('请求url/' + newVal, function (result) {
console.log(result)
})
}
}
侦听器的格式
- 方法格式的侦听器
- 缺点1:无法在刚进入页面的时候,自动触发!!!
- 缺点2:如果侦听的是一个对象,如果对象中的属性发生了变化,不会触发侦器!!!
- 对象格式的侦听器
- 好处1:可以通过 immediate 选项,让侦听器自动触发!!!
- 好处2:可以通过 deep 选项,让侦听器深度监听对象中每个属性的变化!!!
对象侦听器
immediate 选项语法:
<script>
const vm = new Vue({
el: '#app',
data: {
username: 'admin'
},
// 所有的侦听器,都应该被定义到 watch 节点下
watch: {
// 定义对象格式的侦听器
username: {
// 侦听器的处理函数
handler(newVal, oldVal) {
console.log(newVal, oldVal)
},
// immediate 选项的默认值是 false
// immediate 的作用是:控制侦听器是否自动触发一次!
immediate: true
}
}
})
</script>
deep 选项
语法: 深度侦听 、 侦听的是对象的子属性的变化
<script>
const vm = new Vue({
el: '#app',
data: {
// 用户的信息对象
info: {
username: 'admin',
address: {
city: '北京'
}
}
},
// 所有的侦听器,都应该被定义到 watch 节点下
watch: {
/* info: {
handler(newVal) {
console.log(newVal)
},
// 开启深度监听,只要对象中任何一个属性变化了,都会触发“对象的侦听器”
deep: true
} */
// 如果要侦听的是对象的子属性的变化,则必须包裹一层单引号
'info.username'(newVal) {
console.log(newVal)
}
}
})
</script>
计算属性
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
// 红色
r: 0,
// 绿色
g: 0,
// 蓝色
b: 0
},
methods: {
// 点击按钮,在终端显示最新的颜色
show() {
console.log(this.rgb)
}
},
// 所有的计算属性,都要定义到 computed 节点之下
// 计算属性在定义的时候,要定义成“方法格式”
computed: {
// rgb 作为一个计算属性,被定义成了方法格式,
// 最终,在这个方法中,要返回一个生成好的 rgb(x,x,x) 的字符串
rgb() {
return `rgb(${this.r}, ${this.g}, ${this.b})`
}
}
});
计算属性的特点
特点:
- 定义的时候,要被定义为“方法”
- 在使用计算属性的时候,当普通的属性使用即可
好处:
- 实现了代码的复用
- 只要计算属性中依赖的数据源变化了,则计算属性会自动重新求值!
vue-cli 的使用
安装和使用
npm config set cache "创建的node_cache文件夹所在路径"
选择2.X
选择
vue 项目中 src 目录的构成:
assets 文件夹:存放项目中用到的静态资源文件,例如:css 样式表、图片资源
components 文件夹:程序员封装的、可复用的组件,都要放到 components 目录下
main.js 是项目的入口文件。整个项目的运行,要先执行 main.js
App.vue 是项目的根组件。
vue 项目的运行流程
- App.vue 用来编写待渲染的模板结构
- index.html 中需要预留一个 el 区域
- main.js 把 App.vue 渲染到了 index.html 所预留的区域中
vue 组件
vue 组件的三个组成部分
- template -> 组件的模板结构
- script -> 组件的 JavaScript 行为
- style -> 组件的样式
template
vue 规定:每个组件对应的模板结构,需要定义到 <template> 节点中。
- template 是 vue 提供的容器标签,只起到包裹性质的作用,它不会被渲染为真正的 DOM 元素
- template 中只能包含唯一的根节点
script
<script>
// 默认导出。这是固定写法!
export default {
// data 数据源
// 注意:.vue 组件中的 data 不能像之前一样,不能指向对象。
// 注意:组件中的 data 必须是一个函数
data() {
// 这个 return 出去的 { } 中,可以定义数据
return {
username: 'admin'
}
},
methods: {
chagneName() {
// 在组件中, this 就表示当前组件的实例对象
console.log(this)
this.username = '123'
}
},
// 当前组件中的侦听器
watch: {},
// 当前组件中的计算属性
computed: {},
// 当前组件中的过滤器
filters: {}
}
</script>
style
<style lang="less">
.test-box {
background-color: pink;
h3 {
color: red;
}
}
</style>
组件之间的父子关系
使用组件的三个步骤
步骤1:在<script> 节点中使用 import 语法导入需要的组件
import Left from '@/components/Left.vue'
// 2. 注册组件
components: {
Left,
Right,
Test
}
<div class="box">
<!-- 渲染 Left 组件和 Right 组件 -->
<!-- 3. 以标签形式,使用注册好的组件 -->
<Left></Left>
<Right></Right>
</div>
vscode中配置@路径提示插件 可以参看网上教程 注意:开发的那个项目,就定位到那个项目,然后用vscode打开。(不要有与这个项目无关的文件),不然@路径提示将失效
通过 components 注册的是私有子组件
注册全局组件
在 vue 项目的 main.js 入口文件中,通过 Vue.component() 方法,可以注册全局组件。示例代码如下:
// 导入需要被全局注册的那个组件
import Count from '@/components/Count.vue'
//参数一:注册名称 参数二:需要注册全局的哪个组件
Vue.component('MyCount', Count)
组件的 props
props: ['自定义属性']
<MyCount :init="6"></MyCount>
加 : 为数值 不加为字符串
data() {
return {
// 把 props 中的 init 值,转存到 count 上
count: this.init
}
}
props: {
// 自定义属性A : { /* 配置选项 */ },
// 自定义属性B : { /* 配置选项 */ },
// 自定义属性C : { /* 配置选项 */ },
init: {
// 如果外界使用 Count 组件的时候,没有传递 init 属性,则默认值生效
default: 0,
// init 的值类型必须是 Number 数字
type: Number,
// 必填项校验
required: true
}
},
组件之间的样式冲突问题
默认情况下,写在 .vue 组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。
解决组件样式冲突的问题
<style lang="less" scoped>
// h5[data-v-3c83f0b7]
// [data-v-3c83f0b7] h5
// 当使用第三方组件库的时候,如果有修改第三方组件默认样式的需求,需要用到 /deep/
/deep/ h5 {
color: pink;
}
组件的生命周期
生命周期 & 生命周期函数
// created 生命周期函数,非常常用。
// 经常在它里面,调用 methods 中的方法,请求服务器的数据。
// 并且,把请求到的数据,转存到 data 中,供 template 模板渲染的时候使用!
组件之间的数据共享
- 父子关系
- 兄弟关系
//父组件
<Left :msg="message" :user="userinfo"></Left>
data() {
return {
message: 'hello',
userinfo: { name: 'zs', age: 18 },
}
//子组件
<p>msg 的值是:{{ msg }}</p>
<p>user 的值是:{{ user }}</p>
props: ['msg', 'user']
//子组件
export default {
data() {
return {
// 子组件自己的数据,将来希望把 count 值传给父组件
count: 0
}
},
methods: {
add() {
// 让子组件的 count 值自增 +1
this.count += 1
// 把自增的结果,传给父组件 定义事件numchange名字
this.$emit('numchange', this.count)
}
}
//父组件
<Right @numchange="getNewCount"></Right>
data() {
return {
// 定义 countFromSon 来接收子组件传递过来的数据
countFromSon: 0
}
},
methods: {
// 获取子组件传递过来的数据
getNewCount(val) {
console.log('numchange 事件被触发了!', val)
this.countFromSon = val
}
}
- 创建 eventBus.js 模块,并向外共享一个 Vue 的实例对象
import Vue from 'vue' export default new Vue()
- 在数据发送方,调用 bus.$emit('事件名称', 要发送的数据) 方法触发自定义事件
<button @click="send">发给 Right</button> // 1. 导入 eventBus.js 模块 import bus from './eventBus.js' export default { data() { return { str: `hello` } }, methods: { send() { // 2. 通过 eventBus 来发送数据 bus.$emit('share', this.str) } }
- 在数据接收方,调用 bus.$on('事件名称', 事件处理函数) 方法注册一个自定义事件
// 1. 导入 eventBus.js 模块 import bus from './eventBus.js' export default { data() { return { msgFromLeft: '' } }, created() { // 2. 为 bus 绑定自定义事件 bus.$on('share', val => { this.msgFromLeft = val }) } }