Vue 系列笔记第三篇,陆续更新,✌✌专栏阅读:
> Vue「一」—— 前端工程化 与 webpack 的基本使用及常用配置
> Vue「二」—— vue 基本使用 、 vue 指令与过滤器
watch 侦听器 允许开发者监视数据的变化,从而针对数据的变化做特定的操作。也就是 当数据发生变化时,及时做出响应处理 。
下面是采取方法格式来定义侦听器,这种方法比较简便常用。此外,如果遇到某些特殊需求时,也可采取对象格式来定义侦听器(后文介绍)。
<div id="app">
<input type="text" v-model="username">
div>
<script>
const vm = new Vue({
el: "#app",
data: {
username: ''
},
// 侦听器定义在 watch 节点下
watch: {
username(newVal, oldVal) {
console.log('', newVal, oldVal);
}
}
})
script>
几个注意点
此前侦听器的写法是方法格式的写法,也就是直接将对应数据名作为方法名来写函数。这种方法是最常用的,因为它比较简便。
你也可以利用对象格式来定义 watch 侦听器,如下:
watch: {
username: {
// handler 是固定写法,表示当 username 的值变化时,自动调用 handler 处理函数
handler(newVal, oldVal) {
// 。。。
}
}
}
这种语法下,需要将侦听器的响应处理写在 handler(){}
方法内。
默认情况下,组件在初次加载完毕后不会调用 watch 侦听器。如果想让 watch 侦听器立即被调用,则需要使用 immediate 选项 。
watch: {
username: {
handler(newVal, oldVal) {
console.log(newVal);
},
// 默认 false, 控制侦听器是否自动触发
imediate: true
}
}
如果 watch 侦听的是一个对象,如果对象中的 属性值发生了变化,则 无法被监听 到。此时需要使用 deep 选项 。
watch: {
info: {
handler(newVal, oldVal) {
console.log(newVal.username);
},
// 开启深度监听,只要对象中任何属性变化,都会触发
// deep 默认值为 false
deep: true
}
}
注意:这里的 newVal 是 info 对象,而不是变化的属性值。
如果只想监听对象中 单个属性 的变化,则可以按照如下的方式定义 watch 侦听器。
watch: {
'info.username': {
handler(newVal, oldVal) {
console.log(newVal);
}
}
}
计算属性指的是通过一系列运算之后,最终得到一个属性值。这个动态计算出来的属性值可以被模板结构或 methods 方法使用。
所有的计算属性都要定义在 computed 节点之下,计算属性在定义时要定义成方法格式。如下所示:
<div class="box" :style="{ backgroundColor: rgb }">
{
{ rgb }}
div>
var vm = new Vue({
el: '#app',
data: {
r: 0, g: 0, b: 0
},
computed: {
rgb() {
return `rgb(${
this.r},${
this.g},${
this.b})`;
}
}
});
两点好处:
单页面应用程序 (Single Page Application)简称 SPA,指的是一个 Web 网站只有唯一的一个 HTML 页面,所有的功能与交互都在这唯一的一个页面内完成。
如上图所示,整个项目都是通过唯一一个 HTML 页面 index.html 来呈现的,这就叫做单页面应用程序。
vue-cli 是 Vue.js 开发的标准工具。它简化了程序员基于 webpack 创建工程化 Vue 项目的过程。
vue-cli 官网 是这样介绍的:Vue CLI 致力于将 Vue 生态中的工具基础标准化。它确保了各种构建工具能够基于智能的默认配置即可平稳衔接,这样你可以专注在撰写应用上,而不必花好几天去纠结配置的问题。
vue-cli 是 npm 上的一个 全局包,可以通过 npm 进行安装:
npm install -g @vue/cli
vue create 项目名称
assets 文件夹
:存放项目中用到的静态资源文件,例如:css 样式表、图片资源。
components 文件夹
:存放封装的、可复用的组件。
main.js
:项目的入口文件。整个项目的运行,要先执行 main.js。
App.vue
: 项目的根组件。
在工程化的项目中,vue 要做的事情很单纯:通过 main.js 把 App.vue 渲染到 index.html 的指定区域中。
组件化开发 指的是:根据封装的思想,把页面上 可重用的 UI 结构 封装为组件,从而方便项目的开发和维护。
vue 是一个 支持组件化开发 的前端框架。vue 中规定:组件的后缀名是 .vue。之前接触到的 App.vue 文件本质上就是一个 vue 的组件。
每个 .vue 组件都由 3 部分构成,分别是:
template
:组件的模板结构script
:组件的 JavaScript 行为style
:组件的样式
1. template
vue 规定:每个组件对应的 模板结构,需要定义到 节点中。如下:
<template>
template>
❗❗ 注意:
template
是 vue 提供的容器标签,只起到 包裹 性质的作用,它不会被渲染为真正的 DOM 元素template
中只能包含 唯一的根节点
2. script
vue 规定:开发者可以在 节点中封装组件的 JavaScript 业务逻辑 。如下:
<script>
// 默认导出,固定写法
export default {
data() {
return {
// return 中定义数据
};
},
// 组件中的方法
methods: {
},
// 组件中的侦听器
watch: {
},
// 组件中的计算属性
computed: {
},
// 组件中的过滤器
filters: {
},
};
script>
❗❗ 注意:
export default {}
所导出的对象中。
3. style
组件内的 节点是可选的,开发者可以在
节点中 编写样式 美化当前组件的 UI 结构。如下:
<style>
/* 定义样式 */
style>
style 中支持 less 语法,可以这么做:
在 标签上添加
lang="less"
属性,即可使用 less 语法编写组件的样式:
<style lang="less">
/* 定义 less 语法的样式 */
style>
使用组件的三个步骤
在 App.vue 文件中进行如下操作,即可将 Left 和 Right 组件嵌套在 App 组件中:
通过 components 注册的是 私有子组件
例如,在组件 A 的 components 节点下,注册了组件 F。则组件 F 只能用在组件 A 中;不能被用在组件 C 中。
可以看出,如果有一个组件频繁的被用到,就变得很麻烦,需要每次引入。这时,我们可以使用下面所要介绍的 全局组件 。
注册 全局组件
在 vue 项目的 main.js 入口文件中,通过 Vue.component()
方法,可以注册全局组件。这样以后每次使用时,不再需要重复注册,一劳永逸。
例如,这里打算将 Count.vue 设为全局组件,可以在 main.js 入口文件中这样设置:
此后,在其他组件中使用到这个全局组件 Count.vue 时,只需写标签
即可。
props 是组件的 自定义属性,在封装通用组件的时候,合理地使用 props 可以极大的提高组件的复用性。
在 Count.vue 组件中设置自定义属性 init
:
export default {
// props 是"自定义属性",允许使用者通过自定义属性,为当前组件指定初始值
// 自定义属性可以定义多个,可以取任意合法名称
props: ['init'],
data() {
return {
// 数据
}
},
}
当使用到 MyCount 组件(上面的 Count.vue)时,就可以这样定义自定义属性:
<MyCount init="6">MyCount>
❗❗ 注意:上面的 init
被赋值了一个字符串 "6"
,而不是数字 6
。这时,如果你想要的赋值是数字型,可以结合 v-bind
来使用,写成如下形式:
<MyCount :init="6">MyCount>
此外,再强调几点 props 使用事项
1. props 是只读的
vue 规定:组件中封装的 自定义属性是只读的,程序员不能直接修改 props 的值,否则会直接报错。
<button @click="init += 1">+1</button>
如上代码,点击按钮使得自定义属性 init
完成自增时,发现网页给出报错:
要想修改 props 的值,可以 把 props 的值转存到 data 中,因为 data 中的数据都是可读可写的。
data() {
return {
// 把 props 中的 init 值,转存到 count 上
count: this.init,
};
},
2. props 的其他可选项
在声明自定义属性时,还可以将其指定为 对象形式 而非数组形式,同时指定如下可选项:
props: {
init: {
// 如果外界使用 Count 组件的时候,没有传递 init 属性,则默认值生效
default: 0,
// init 的值类型必须是 Number 数字
type: Number,
// 必填项校验
required: true
}
},
默认情况下,写在 .vue 组件中的 样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。
导致组件之间样式冲突的根本原因是:
如何解决样式冲突问题呢?
为了提高开发效率和开发体验,vue 为 style 节点 提供了 scoped 属性,从而防止组件之间的样式冲突问题。
<style lang="less" scoped>
h3 {
color: red;
}
style>
而它的原理就是,scoped 属性自动为每个组件分配了唯一的 “ 自定义属性 ”。该组件中的 DOM 标签和 style 样式都应用了这个自定义属性,这样就解决了样式冲突的问题。
/deep/ 样式穿透
如果给当前组件的 style 节点添加了 scoped 属性,则当前组件的样式 对其子组件是不生效的。如果想让某些样式对子组件生效,可以使用 /deep/ 深度选择器。
<style>
/* 当使用第三方组件库的时候,如果有修改第三方组件默认样式的需求,需要用到 /deep/ */
/deep/ h5 {
color: pink;
}
style>
应用场景:通过父组件直接修改子组件样式。一般在引入第三方库时,需要修改第三方库中元素样式时使用,从而避免了查找第三方库源码修改的困难。