vue脚手架(vue-cli),vue2,vue3,ref引用,路由和路由插件(vue-router),路由导航守卫,插槽

一. 单页面应用程序

SPA是单页面应用程序

vue脚手架(vue-cli),vue2,vue3,ref引用,路由和路由插件(vue-router),路由导航守卫,插槽_第1张图片

如何快速创建vue的SPA项目

vue官方提供了两种快速创建工程化的SPA项目的方式

1. 基于vite创建SPA项目

2. 基于vue-cli创建SPA项目

vite

vue-cli

支持的vue版本

仅支持vue3.x

支持3.x和2.x

是否支持webpack

运行速度

较慢

功能完整度

小而巧

大而全

是否建议在企业级开发中使用

目前不建议

建议在企业级开发中使用

1. 基于vite创建SPA项目

1. npm init vite-app 项目名称

2. cd 项目名称

3. npm install

4. npm run dev

2. 梳理项目结构

使用vite创建的项目结构中:

1. node_modules目录用来存放第三方依赖包

2. public是公共的静态资源目录

3. src是项目的源代码目录(程序员写的所有代码都要放在此目录下)

4. .gitignore是Git的忽略文件

5. index.html是SPA单页面应用程序中唯一的HTML页面

6. package.json是项目的包管理配置文件

src这个项目源代码目录之下,包含了如下的文件和文件夹

assets目录用来存放项目中所有的静态资源文件(CSS,fonts等)

components目录用来存放项目中所有的自定义组件

App.vue是项目的根组件

index.css是项目的全局样式表文件

main.js是整个项目的打包入口文件

3. vite项目的运行流程

vue要做的事情:通过main.js把APP.vue渲染到index.html的指定区域

其中:

1. App.vue用来编写待渲染的模板结构

2. index.html中要预留一个el区域

3. main.js把App.vue渲染到了index.html所预留的区域

按照vue3.x的标准用法,把App.vue中的模板渲染到index.html页面的el区域

二. vue-cli

vue脚手架(vue-cli),vue2,vue3,ref引用,路由和路由插件(vue-router),路由导航守卫,插槽_第2张图片

vue脚手架用于自动生成vue和webpack的项目模板;

vue脚手架是一个快速构建vue项目的工具,可以自动安装vue所需要的插件,避免手动安装各种插件,以及寻找各种cdn并一个个引入的麻烦。

vue脚手架指的是vue-cli,vue-cli是由Vue提供的一个官方cli,专门为单页面应用快速搭建繁杂的脚手架。是vue官方提供的,快速生成vue工程化项目的工具

它是用于自动生成vue.js+webpack的项目模板,是为现代前端工作流提供了 batteries-included 的构建设置。只需要几分钟的时间就可以运行起来并带有热重载,保存时 lint 校验,以及生产环境可用的构建版本。

vue-cli是Vue.js开发的标准工具。它简化了程序员基于webpack创建工程化的Vue项目的过程。

vue-cli官网上说:程序员可以专注在撰写应用上,而不必花好几天去纠结webpack配置的问题。

1. 特点

1. 开箱即用;2. 基于webpack;3. 功能丰富易于扩展;4. 支持创建vue2和vue3的项目

vue-cli是基于Node.js开发出来的工具,因此需要使用npm将它安装为全局可用的工具。

vue --version查看vue-cli的版本,检验是否安装成功。

2. vue-cli创建项目的方式

#基于命令行的方式创建vue项目

vue create 项目名称

#基于可视化面板创建vue项目

vue ui

vue ui的本质:通过可视化的面板采集到用户的配置信息后,在后台基于命令行的方式自动初始化项目。

3. vue/cli的使用

1. 检查自己电脑里有没有vue

1. 1 检查自己是否装了npm

1.2  检查自己是否装了vue

vue脚手架(vue-cli),vue2,vue3,ref引用,路由和路由插件(vue-router),路由导航守卫,插槽_第3张图片

1.3  如果没有装的话,执行如下命令全局安装

npm install -g @vue/cli

2. 创建项目 

切换到指定目录,用命令创建项目

使用cmd命令先切换到F://vueProject(你想要创建项目的文件夹)下,再使用创建项目命令。

使用vue create 后面的项目名,名字不要大写。(否则会有警告提示)

F:
cd vueProject
vue create vuetest

创建完项目→选择自定义(空格键选中、取消选中 )→选择babel、router、vuex(根据需求) →使用history模式的路由 →选中In dedicated config files(babel等配置写在单独的文件中)等等,根据自己的需要选就行。

3. 启动项目

不一定是dev,也有可能是serve,具体可以看package.json配置文件中写的是什么。

vue run dev

4. 打包项目

npm run build

4. 项目运行流程

//main.js核心代码
//1. 导入Vue
import Vue from 'vue'

//2. 导入App.vue
import App from './App.vue'

// 提示:当前处于什么环境(生产环境/开发环境)
Vue.config.productionTip = false

//3. 实例化Vue,将App.vue渲染到index.html容器中
new Vue ({
    render: h => h(App),
}).$mount('#app')


// el:'#app'的作用,和$mount('选择器')作用一致,用于指定Vue所管理容器
new Vue ({
    el:'#app',
})

new Vue ({
    render: (createElement) => {
        //基于App创建元素
        renturn createElement(App)
    }
}).$mount('#app')

//箭头函数只有一个形参,可以省略小括号;返回值只有一个,可以省略大括号。所以上述代码可以改写成
new Vue ({
    render: createElement => createElement(App)
}).$mount('#app')

//createElement只是一个形参,你把它写成什么都行,写成h就变成了
new Vue({
    render: h => h(App)
}).$mount('#app')

5. propxy跨域代理

接口的跨域问题:

vue项目运行的地址:http://localhost:8080/

API接口运行的地址:https://www.escook.cn/api/users

如果后端没有开启cors资源跨域共享的话,前端可以通过代理的方式来解决跨域的问题。

通过vue-cli创建的项目,在遇到接口跨域问题时,可以通过代理的方式来解决。

1. 把axios的请求根路径设置为vue项目的运行地址(接口请求不再跨域)

2. vue项目发现请求的接口不存在,把请求转交给proxy代理

3. 代理把请求根路径替换为devServer.proxy属性的值,发起真正的数据请求

4. 代理把请求到的数据,转发给axios

注意:devServer.proxy提供的代理功能,仅在开发调试阶段生效,

项目上线发布时,依旧需要API接口服务器开启CROS跨域资源共享。

6. ESlint代码规范

代码规范:一套写代码的约定规则。例如:赋值符号的左右是否需要空格...

JavaScript Standard Style规范说明https://standardjs.com/rules-zhcn.html

// 下面是这份规则中的一小部分

字符串使用单引号'abc'
无分号 const name = 'zs'
关键字后加空格 if (name = 'ls') {...}
函数名后加空格 function name (arg) {...}
坚持使用全等 === 摒弃 ==
...

 解决代码规范错误的两种方案:手动修正+自动修正

1. 手动修正

根据错误提示来一项一项手动修改纠正,如果不认识就去ESLint规则表中查找具体含义。

vue脚手架(vue-cli),vue2,vue3,ref引用,路由和路由插件(vue-router),路由导航守卫,插槽_第4张图片

2. 自动修正 

基于vscode插件ESLint高亮错误,并通过配置自动帮助我们修复错误

//当保存的时候,eslint自动帮我们修复错误
"editor.codeActionsOnSave": {
    "source.fixAll": true
},
//保存代码时不自动格式化
"editor.formatOnSave": false

三. Vue

1. 概念

Vue是一套用于构建用户界面的框架。(帮程序员往页面里面填充数据的)

传统的web前端开发中,是基于jQuery+模板引擎的方式来构建用户界面的。

框架是一套现成的解决方案,程序员只能遵守框架的规范,去编写自己的业务功能。

学习Vue,就是学习Vue框架中规定的语法。

vue脚手架(vue-cli),vue2,vue3,ref引用,路由和路由插件(vue-router),路由导航守卫,插槽_第5张图片

 vue脚手架(vue-cli),vue2,vue3,ref引用,路由和路由插件(vue-router),路由导航守卫,插槽_第6张图片

MVVM是vue实现数据驱动视图和双向数据绑定的核心原理。

Model表示当前页面渲染时所依赖的数据源

View表示当前页面所渲染的DOM结构

ViewModel表示vue的实例,它是MVVM的核心。它把当前页面的数据源(Model)和页面结构(View)连接在了一起。

2. vue要做什么

在工程化的项目中,vue要做的事,就是通过main.js把App.vue渲染到index.html的指定区域

其中,

APP.vue用来编写待渲染的模板结构

index.html中需要预留一个el区域

main.js把App.vue渲染到了index.html所预留的区域中

3. vue基本使用步骤

1. 导入vue.js的script脚本文件(开发版本/生产版本)

2. 在页面中声明一个将要被vue所控制的DOM区域

3. 创建vm实例对象(vue实例对象)

4. 指定配置项el,data=>渲染数据



{{ username }}

vue官方提供的vue-devtools调试工具,能够方便开发者对vue项目进行调试与开发。

极简插件网址:https://chrome.zzzmh.cn/index

注意:vue2和vue3的浏览器调试工具不能交叉使用!

4. 最常用的vue组件库

PC端: Element UI
View UI
移动端: Mint UI
Vant

Element UI

是饿了么前端团队开源的一套PC端vue组件库。支持vue2和vue3的项目中使用。

vue2的项目使用旧版的Element UI(https://element.eleme.cn/#/zh-CN)

vue3的使用旧版的Element Plus(https://element-plus.gitee.io/#/zh-CN)

在vue2的项目中安装element-ui

1. npm i element-ui -S

2. 引入element-ui

// 完整引入
import ElementUI from ‘element-ui’
//导入样式表
import ‘element-ui/lib/theme-chalk/index.css’
Vue.use(ElementUI)

// 按需引入
// 借助babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。
npm install babel-plugin-component -D
// 修改根目录下的babel.config.js配置文件,新增plugin节点:
plugins: [
    [
        ‘component’,
        {
            libraryName:’element-ui’,
            styleLibraryName:’theme-chalk’,
        },
    ],
],
// 如果只希望引入部分组件,比如button,那么需要在main.js中写入以下内容:
import {Button} from ‘element-ui’
Vue.component(Button.name,Button)

把组件的导入和注册封装为独立的模块

在src目录下,新建element-ui/index.js模块,并声明如下的代码:

import Vue from ‘vue’
import {Button,Input} from ‘element-ui’

// 注册需要的组件
Vue.use(Button)
Vue.use(Input)

// 在main.js中导入
import ‘.//element-ui’

5. 配置axios

1. 在vue3的项目中全局配置axios

import axios from ‘axios’

axios.defaults.baseURL=’https://www.escook.cn’

app.config.globalProperties.$http=axios

2. 在vue2的项目中全局配置axios

// 需要在main.js入口文件中,通过Vue构造函数的prototype原型对象全局配置axios

import axios from ‘axios’

axios.defaults.baseURL=’https://www.escook.cn’

Vue.prototype.$http=axios

6. axios拦截器

拦截器会在每次发起ajax请求和得到响应的时候自动被触发。

应用场景:

1. Token身份认证

2. Loading效果

1. 配置请求拦截器

通过axios.interceptors.request.use(成功的回调,失败的回调)可以配置请求拦截器。

1. 请求拦截器——Token认证

import axios from ‘axios’

axios.defaults.baseURL=’https://escook.cn’

//配置请求的拦截器
axios.interceptors.request.use(config = >{
    //为当前请求配置Token认证字段
    config.headers.Authorization=’Bearer xxx’
    return config
})

Vue.prototype.$http=axios

2. 请求拦截——Loading效果

//按需导入Loading效果组件
import { Loading } from ‘element-ui’

//声明变量,用来存储Loading组件的实例对象
let loadingInstance = null

//配置请求的拦截器
axios.interceptors.request.use(config = >{
    //调用Loading组件的service()方法,创建Loading组件的实例,并全屏展示loading效果
    loadingInstance=Loading.service({ fullscreen: true })//是否全屏
    return config
})

3. 配置响应拦截器

通过axios.interceptors.response.use(成功的回调,失败的回调)可以配置响应拦截器。

// 响应拦截器——关闭Loading效果

// 调用Loading实例提供的close()方法即可关闭Loading效果

axios.interceptors.response.use(response = >{
    loadingInstance.close()
    return response   
})

四. Vue指令

Vue会根据不同的指令,针对标签实现不同的功能。

指令:带有v-前缀的特殊标签属性。

1. 内容渲染指令

用来辅助开发者渲染DOM元素的文本内容

v-text,   //会覆盖默认文本内容   只能渲染文本内容

{{}},插值表达式,   //只能渲染纯文本内容

v-html   //可以把包含HTML标签的字符串渲染为页面的HTML元素

2. 属性绑定指令(v-bind)

1. 作用

动态设置html的标签属性→src,url,title...

2. 语法

v-bind: 属性名=“表达式”,v-bind:简写为英文的:






data:{
    inputValue:’请输入内容’,
    imgSrc:’http://cn...’
}

3. v-bind对样式控制的增强

1. 操作class

语法::class="对象/数组"

1. 对象→键就是类名,值是布尔值。如果值为true,有这个类,否则没有这个类

适用场景:一个类名,来回切换

MyDeep组件

data() { return { classObj:{ isItalic: true, isDelete: false, } } } ​

2. 数组→数组中所有的类,都会添加到盒子上,本质就是一个class列表

适用场景:批量添加或删除

MyDeep组件

data() { return { isItalic: true, isDelete: false, } }

3. 用三元表达式动态为元素绑定class的类名

MyDeep组件

data() { return {isItalic:true} } .thin {    //字体变细 font-weight:200; } .italic {    //倾斜字体 font-style: italic; }

2. 操作style

语法::style="样式对象"

适用场景:某个具体属性的动态设置

:style的对象语法十分直观——看着非常像CSS,但其实是一个JavaScript对象。CSS property名可以用驼峰式或短横线分隔来命名。

黑马程序员
data() { return { active: ‘red’, fsize: 30, bgcolor: ‘pink’, } }

3. 事件绑定指令(v-on)

v-on:简写为@,为DOM元素绑定事件监听。

1. 作用

注册事件=添加监听+提供处理逻辑

2. 语法

v-on:事件名 = “内联语句”

// 鼠标点击count变化


//鼠标划入count变化

v-on:事件名 = “methods中的函数名”



const app = new Vue({
    el:'#app',
    data: {
        //提供数据
        count: 100
    },
    methods: {
        //提供处理逻辑函数
        fn() {
            console.log('提供逻辑代码')
        }
    }
})

注意:原生DOM对象有onclick, oninput, onkeyup等原生事件,替换为vue的事件绑定形式之后,分别为:v-on:click, v-on:input, v-on:keyup

通过v-on绑定的事件处理函数,需要在methods节点中进行声明

v-on 调用传参





const app = new Vue({
    el:'#app',
    data:{
        money:100
    },
    method:{
        buy(price) {
            this.money -= price
        }
    }
})

v-on指令所绑定的事件处理函数中,同样可以接收到事件对象event

const vm = new Vue({
    el: ‘#app’,
    data: { count:0 },
    methods: {
        addCount(e) {   //事件处理函数的名字
            const nowBgColor = e.target.style.backgroundColor
            e.target.style.backgroundColor = nowBgColor === ‘red’ ? ‘ ’ : ‘red’
            
            //this表示当前new出来的vm实例对象
            //通过this可以访问到data中的数据
            this.count +=1
        },
    },
})

$event是vue提供的特殊变量,用来表示原生的事件参数对象event。$event可以解决事件参数对象event被覆盖的问题。

count的值为:{{ count }}

methods: { //在形参处用e接收传递过来的原生事件参数对象$event addNewCount(step,e) { const nowBgColor = e.target.style.backgroundColor e.target.style.backgroundColor = nowBgColor === ‘red’ ? ‘ ’ : ‘red’ this.count += step } }

4. vue指令修饰符

通过"."指明一些指令后缀,不同后缀封装了不同的处理操作→简化代码

1. 按键修饰符

@keyup.enter→键盘回车监听





2. v-model修饰符

v-model.trim→去除首尾空格

v-model.number→转数字

.number 自动将用户的输入值转为数值类型
.trim 自动过滤用户输入的首尾空白字符串
.lazy 在”change”时而非”input”时更新(文本框失去焦点时才更新)

3. 事件修饰符

@事件名.stop→阻止冒泡

@事件名.prevent→阻止默认行为 

.prevent 阻止默认行为
.stop 阻止事件冒泡
.capture 以捕获模式触发当前的事件处理函数
.once 绑定的事件只触发一次
.self 只有在event.target是当前元素自身时触发事件处理函数

5. 双向绑定指令(v-model)

1. 作用

表单元素使用,双向数据绑定→可以快速获取或设置表单元素内容。

数据变化→视图自动更新

视图变化→数据自动更新

2. 语法

v-model = '变量'

账户: 密码:
//name节点,name属性指向的是当前组件的名称,建议每个单词的首字母大写

//data节点,vue组件渲染期间需要用到的数据,可以定义在data节点中,data方法中return出去的对象,就是当前组件渲染期间需要用到的数据对象
data() {
    return {
        username:’哇哈哈’
    }
}
//methods节点,组件中的事件处理函数,必须定义到methods节点中。
methods: {
    addCount() {
        this.count++
    },
}

vue规定,组件内的 // 2. 安装依赖包 less less-loader yarn add less less-loader -D

3. vue的组件注册

1. 组件的注册

1. 组件之间可以进行相互的引用,组件引用的原则:先注册,再使用

2. 全局注册组件,被全局注册的组件,可以在全局任何一个组件内使用

3. 局部注册组件,被局部注册的组件,只能在当前注册的范围内使用

2. main.js文件的作用

main.js是项目的入口文件,项目中所有的页面都会加载main.js。

主要有三个作用:

1.实例化Vue

2.放置项目中经常会用到的插件和CSS样式

3.存储全局变量

3. 组件注册时名称的大小写

在进行组件的注册时,定义组件名称的方式有两种:

1. 短横线命名法(例如my-swiper和my-search)

2. 帕斯卡命名法或大驼峰命名法(例如MySwiper和MySearch)

帕斯卡命名法的特点:既可以严格按照帕斯卡名称进行使用,又可以转化为短横线名称进行使用。

在实际开发中,推荐使用帕斯卡命名法为组件注册名称,因为它的适用性更强。

在注册组件期间,除了可以直接提供组件的注册名称之外,还可以把组件的name属性作为注册后组件的名称。

4. 全局组件注册

首先要创建.vue文件(三个组成部分),然后再在main.js中进行全局注册。

// 假设这里是一个components文件夹,里面有一个组件
HmButton.vue


// 在main.js文件中

// 导入需要全局注册的组件
import HmButton from './components/HmButton'
// 调用Vue.component进行全局注册
// Vue.component('组件名', 组件对象)
Vue.component('HmButton', HmButton)
//1. 在main.js中导入Swiper和Test两个组件

import Swiper from ‘./components/MySwiper.vue’
import Test from ‘./components/MyTest.vue’

//2. 在main.js中调用app实例的component()方法,在全局注册my-swiper和my-test两个组件
app.component(‘my-swiper’, Swiper)
app.component(‘my-test’, Test)



//3. 在其他组件中,直接以标签的形式,使用刚才注册的全局组件即可

2. 在main.js中用Vue.use()

新建一个userdata目录 下面有一个index.vue和index.js文件

index.vue文件是常规的vue文件

index.js文件注册该组件:

//这里是index.js文件
//这里,将自定义组件注册成插件了
import index from './index.vue'
const indexLists = {
    install: function(Vue) {

        // 注册并获取组件,然后在main.js中引用,再Vue.use()就可以了
        Vue.component('indexLists', index)
    }
}
export default indexLists

在main.js引用并注册: 

import userdata from '@/components/index.js'
Vue.use(userdata);

5. 局部组件注册

// 假设这是compoents文件夹,下面有三个.vue文件
HmFooter.vue
HmHeader.vue
HmMain.vue




6. 全局方法注册

在目录下面建立一个common.js文件

//这里是common.js文件
const obj={
    fun(){
        console.log('hello word')
    }
}
export default obj

//这里是别的文件
import comm form './common.js'
Vue.protopyte.$common = comm
this.$common.fun1() // hello word

4. 组件的生命周期

1. 组件的运行过程

开始→import导入组件→components注册组件→以标签形式使用组件→在内存中创建组件的是对象→把创建的组件实例渲染到页面上→组件切换时销毁需要被隐藏的组件→结束。

组件的生命周期指的是:组件从创建运行(渲染)→销毁的整个过程,强调的是一个时间段。

2. 监听组件的不同时刻

vue框架为组件内置了不同时刻的生命周期函数,生命周期函数会伴随着组建的运行而自动调用。1. 当组件在内存中被创建完毕后,会自动调用created函数(发ajax请求数据)

2. 当组件被成功的渲染到页面上之后,会自动调用mounted函数(操作DOM)

3. 当组件被销毁完毕后,会自动调用unmounted函数

3. 监听组件的更新

当组件的data数据更新之后,vue会自动重新渲染组件的DOM结构,从而保证View视图展示的数据和Model数据源保持一致

当组件被重新渲染完毕之后,会自动调用updated生命周期函数。

4. 组件生命周期函数

是由vue框架提供的内置函数,会伴随着组件的生命周期,自动按次序执行。

1. 组件创建阶段

(组件生命周期的第一个阶段)

beforeCreate 组件的props/data/methods尚未被创建,都处于不可用状态
created 组件的props/data/methods已创建好,都处于可用的状态,但是组件的模板结构尚未生成!
beforeMount 将要把内存中编译好的HTML结构渲染到浏览器中。此时浏览器中还没有当前组件的DOM结构
mounted 已经把内存中的HTML结构,成功渲染到了浏览器之中。此时浏览器中已然包含了当前组件的DOM结构

2. 组件运行阶段

(组件生命周期的第二个阶段)

beforeUpdate 将要,根据变化过后,最新的数据,重新渲染组件的模板结构
updated 已经根据最新的数据,完成了组件DOM结构的重新渲染

3. 组件销毁阶段

(组件生命周期的第三个阶段)

beforeDestory 将要销毁此组件,此时尚未销毁,组件还处于正常工作的状态
destoryed 组件已经被销毁,此组件在浏览器中对应的DOM结构已被完全移除

5. keep-alive对应的生命周期

keep-alive是Vue的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁

keep-alive是一个抽象组件,它自身不会渲染成一个DOM元素,也不会出现在父组件链中。

keep-alive保持状态

默认情况下,切换组件时,无法保持组件的状态。

此时可以使用vue内置的组件保持动态组件的状态

当组件被缓存时,会自动触发组件的deactivated生命周期函数。

当组件被激活时,会自动触发组件的activated生命周期函数。

keep-alive的三个属性:include,exclude,max 

keep-alive的include属性

include属性用来指定:只有名称匹配的组件会被缓存。多个组件名之间使用英文的逗号分隔。

keep-alive的exclude属性

组件名数组,任何匹配的组件都不会被缓存

keep-alive的max属性

最多可以缓存多少组件实例

5. 动态组件

vue提供了一个内置的组件,专门用来实现动态组件的渲染。

指的是动态切换组件的显示与隐藏。vue提供了一个内置的组件,专门用来实现组件的动态渲染。

是组件的占位符

通过is属性动态指定要渲染的组件名称

6. 组件之间的样式冲突

1. 什么是样式冲突

默认情况下,写在.vue组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。

1. 全局样式:默认组件中的样式会作用到全局。

2. 局部样式:可以给组件加上scoped属性,可以让样式只作用于当前组件。

2. 为什么会有样式冲突

导致组件之间样式冲突的根本原因是:

1. 单页面应用程序,所有组件的DOM结构,都是基于唯一的index.html页面进行呈现的。

2. 每个组件中的样式,都会影响整个index.html页面中的DOM元素。

3. 如何解决样式冲突

1. 为每个组件分配唯一的自定义属性,在编写组件样式时,通过属性选择器来控制样式的作用域。

2. 为了提高开发效率和开发体验,vue为style节点提供了scoped属性,从而防止组件之间的样式冲突问题。

3. 如果给当前组件的style节点添加了scoped属性,则当前组件的样式对其子组件是不生效的。如果想让某些样式对子组件生效,可以使用/deep/深度选择器。

/deep/ .title{
    color:blue;
}

4. 注意:/deep/是vue2.x中实现样式穿透的方案。在vue3.x中推荐使用:deep()替代/deep/

:deep(.title) {
    color: blue;
}

4. scoped原理

1. 当前组件内标签都被添加data-v-hash值的属性

2. css选择器都被添加 [data-v-hash] 的属性选择器

最终效果:必须是当前组件的元素,才会有这个自定义属性,才会被这个样式作用到。

7. data是一个函数

一个组件的data选项必须是一个函数。保证每个组件实例,维护独立的一份数据对象。

每次创建新的组件实例,都会执行一次data函数,得到一个新对象。

//这里是BaseCount.vue组件


// 这里是App.vue组件



可以看到,‘data函数执行了’打印了三次。每次执行都会得到独立的对象。 

8. 组件的props

1. 封装组件的原则

为了提高组件的复用性,在封装vue组件时要遵守如下的规则:

1. 组件的DOM结构,Style样式要尽量复用

2. 组件中要展示的数据,尽量由组件的使用者提供。

props是组件的自定义属性,组件的使用者可以通过props把数据传递到子组件内部,供子组件内部进行使用。

props的作用:父组件通过props向子组件传递要展示的数据。

props的好处:提高了组件的复用性。

2. 在组件中声明props




3. 无法使用未声明的props

如果父组件给子组件传递了未声明的props属性,则这些属性会被忽略,无法被子组件使用。



4. 动态绑定props的值

可以使用v-bind属性绑定的形式,为组件动态绑定props的值。



5. props的大小写命名

组件中,如果使用”camelCase(驼峰命名法)”声明了props属性的名称,则有两种方式为其绑定属性的值。












9. props校验

在封装组件时对外界传递过来的props数据进行合法性的校验,从而防止数据不合法的问题。

使用对象类型的props节点,可以对每个prop进行数据类型的校验。

props: {
    count: Number,
    state: Boolean
}

对象类型的props节点提供了多种数据验证方案,例如:

1. 基础的类型检查

props: {
    propA: String,   字符串类型
    propB: Number,   数字类型
    ...
}

2. 多个可能的类型

如果某个prop属性值的类型不唯一,此时可以通过数组的形式,为其指定多个可能的类型。

props: {
    //propA属性的值可以是“字符串”或“数字”
    propA: [String,Number],
}

3. 必填项校验

如果组件的某个prop属性是必填项,必须让组件的使用者为其传递属性的值。此时,可以通过如下的方式将其设置为必填项。

props: {
    //通过“配置对象”的形式,来定义propB属性的“验证规则”
    propB: {
        //当前属性的值必须是String字符串类型
        type: String,   
        //当前属性的值是必填项,如果使用者没指定propB属性的值,则在终端进行警告提示
        required: true,   
    },
}

4. 属性默认值

props: {
    propC: {
        type: Number,
        //如果使用者没有指定propC的值,则propC属性的默认值为100
        default: 100   
    }
}

5. 自定义验证函数

在封装组件时,可以为prop属性指定自定义的验证函数,从而对prop属性的值进行更加精确的控制:

props: {
    //通过“配置对象”的形式,来定义propD属性的“验证规则”
    PropD: {
        //通过validator函数,对propD属性的值进行校验,“属性的值”可以通过形参value进行接收
        validator(value) {
            //propD属性的值,必须匹配下列字符串中的一个
            //validator函数的返回值为true表示验证通过,false表示验证失败
            return [‘success’, ‘warning’, ‘danger’].indexOf(value) !=-1
        }
    }
}

10. 自定义事件

在封装组件时,为了让组件的使用者可以监听到组件内状态的变化,此时需要用到组件的自定义事件。

只要count值发生变化,立即通过自定义事件的形式,把最新的值发送给组件的使用者。

1. 自定义事件的使用步骤

1. 在封装组件时

1. 声明自定义事件

开发者为自定义组件封装的自定义事件,必须事先在emits节点中声明。

export default {
    //my-counter组件的自定义事件,必须事先声明到emits节点中
    emits: [‘change’],
}

2. 触发自定义事件

在emits节点下声明的自定义事件,可以通过this.$emit(‘自定义事件的名称’)方法进行触发。

export default {
    emits: [‘change’],
    methods: {
        onBtnClick() {
            //当点击+1按钮时,调用this.$emit()方法,触发自定义的change事件
            this.$emit(‘change’)   
        }
    }
}

2. 使用组件时

在使用自定义的组件时,可以通过v-on的形式监听自定义事件





methods: {
    getCount() {
        console.log(‘监听到了count值的变化’)
    }
}

2. 自定义事件传参

在调用this.$emit()方法触发自定义事件时,可以通过第2个参数为自定义事件传参。

export default {
    emits: [‘change’],
    methods: {
        onBtnClick() {
            this.$emit(‘change’, this.count)   //触发自定义事件时,通过第二个参数传参
        },
    },
}

11. 组件之间的数据共享

v-model是双向数据绑定指令,当需要维护组件内外数据的同步时,需要用到。

父子关系:props,$emit

非父子关系:provide&inject,eventbus

在组件上使用v-model的步骤:

1. 父传子:

1. 父组件通过v-bind:属性绑定的形式,把数据传递给子组件

2. 子组件中,通过props接收父组件传递过来的数据

2. 子传父:

1. 在v-bind:指令之前添加v-model指令

2. 在子组件中声明emits自定义事件,格式为update:xxx

3. 调用$emit()触发自定义事件,更新父组件中的数据

1. 组件之间的关系

在项目开发中,组件之间的关系分为如下3种:

父子关系,兄弟关系,后代关系

2. 父子组件之间的数据共享

父→子共享数据

父组件通过v-bind属性绑定向子组件共享数据。同时子组件需要使用props接收数据。

//父组件





//子组件Son.vue


子→父共享数据

子组件通过自定义事件的方式向父组件共享数据。

//子组件




//父组件

父子双向数据同步

父组件在使用子组件期间,可以使用v-model指令维护组件内外数据的双向同步。

//父组件


//子组件
export default {
    props: [‘num’],
    emits: [‘update: num’],
    methods: {
        addN1() {
            this.$emit(‘update:num’,this.num+1)
        }
    },
}

3. 兄弟组件之间的数据共享

兄弟组件之间实现数据共享的方案是EventBus(复杂场景→Vuex)。可以借助于第三方的包miit来创建eventBus对象。

vue脚手架(vue-cli),vue2,vue3,ref引用,路由和路由插件(vue-router),路由导航守卫,插槽_第8张图片

// 这里是utils文件夹下面的EventBus.js文件
// 3.1 首先npm install [email protected]
// 3.2 接着创建公共的EventBus模块
//eventBus.js
//导入miit包
import mitt from ‘mitt’
//创建EventBus的实例对象
const bus = mitt()
//将EventBus的实例对象共享出去
export default bus


// 这里是接收数据的组件
// 3.3 在数据接收方自定义事件
import bus from ‘./eventBus.js’
export default {
    data() { return { count :0 } },
    created() {        
        //调用bus.on()方法注册一个自定义事件,通过事件处理函数的形参接收数据
        bus.on(‘countChange’,(count) => {
            this.count = count
        })
    }
}


// 这里是发送数据的组件
// 3.4 在数据发送方触发事件
import bus from ‘./eventBus.js’
export default{
    data() { return { count :0 } },
    methods:{
        addCount() {
            this.count++
            bus.emit(‘countChange’,this.count)   //调用方法触发事件
        }
    }
}

4. 后代组件之间的数据共享

指的是父节点的组件向其子孙组件共享数据。可以使用provide和inject实现。

provide&inject作用:跨层级共享数据。

1. 父节点通过provide提供数据

export default {
    data() {
        return {
            //1. 定义父组件要向子孙组件共享的数据
            color: ‘red’   
        }
    },
    provide() {
        //2. provide函数return的对象中,包含了要向子孙组件共享的数据   
        return {
            // 普通类型【非响应式】
            color:this.color,
            // 复杂类型【响应式】
            userInfo:this.userInfo,
        }
    },
}

2. 子孙节点可以使用inject数组,接收父级节点向下共享的数据



3. 父节点对外共享响应式的数据

父节点使用provide向下共享数据时,可以结合computed函数向下共享响应式的数据。

import { computed } from ‘vue’
export default {
    data() {
        return {
            color: ‘red’   //1. 定义父组件要向子孙组件共享的数据
        }
    },

    provide() {   //2. provide函数return的对象中,包含了要向子孙组件共享的数据
        return {
            //要共享的数据的名称:要共享的数据的值
            color:computed( ()=>this.color),
        }
    },
}

4. 子孙节点使用响应式的数据

如果父级节点共享的是响应式的数据,则子孙节点必须以.value的形式进行使用。



5. vuex(全局数据共享)

vuex是终极的组件之间的数据共享方案。在企业级的vue项目开发中,vuex可以让组件之间的数据共享变得高效,清晰,且易于维护。

12. prop&data,单向数据流

1. 共同点

都可以给组件提供数据。

2. 区别

data的数据是自己的→随便改

prop的数据是外部的→不能直接改,要遵循单向数据流。

八. Vue组件高级

1. watch侦听器

watch侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作。

开发者需要在watch节点下,定义自己的侦听器。

例如:监视用户名的变化并发起请求,判断用户名是否可用。

export default {
    data() {
        return {username: ‘’ }
    },
    watch: {
        //监听username的值的变化,
        //形参列表中,第一个值是“变化后的新值”,第二个值是“变化之前的旧值”
        username(newVal,oldVal) {
            console.log(newVal,oldVal)
        },
    }
}

2. immediate选项

在默认情况下,组件在初次加载完毕后不会调用watch侦听器。

如果想让watch侦听器立即被调用,则需要使用immediate选项。

watch: {
    //1. 监听username值的变化
    username: {
        //2. hander属性是固定写法:当username变化时,是调用handler
        async handler(newVal,oldVal) {
            const { data:res }=await axios.get(`url地址/${newVal}`)
            console.log(res)
        },
        //3. 表示组件加载完毕后立即调用一次当前的watch侦听器
        immediate: true
    },
}

3. deep选项

当watch侦听的是一个对象,如果对象中的属性值发生了变化,则无法被监听到。此时需要使用deep选项。

data() {
    return {
        info: { username : ‘admin’},  //info中包含username属性
    }
},
watch: {
    info: {   //直接监听info对象的变化
        async handler(newVal, oldVal) {
            const {data:res}=await axios.get(`url地址/${newVal.username}`)
            console.log(res)
        },
        deep: true   //需要使用deep选项,否则username值的变化无法被监听到。
    },
}

4. 监听对象单个属性的变化

如果只想监听对象中单个属性的变化,则可以按照如下方式定义watch监听器。

data() {
    return {
        info: {
            username: ‘admin’,
            password:’’
        },
    }
},

watch: {
    ‘info.username’: {   //只想监听info.username属性值的变化
        async handler(newVal,oldVal) {
            const { data:res }=await axios.get(`url地址/${newVal}`)
            console.log(res)
        },
    },
},

5. 计算属性vs侦听器

计算属性和侦听器侧重的应用场景不同:

计算属性侧重于监听多个值的变化,最终计算并返回一个新值

侦听器侧重于监听单个数据的变化,最终执行特定的业务处理,不需要有任何返回值。

6. ref引用

在Vue里面,以$符号开头的,都是vue的内置成员。

特点:查找范围→当前组件内(更加精确稳定)

querySelector查找范围→整个页面

ref用来辅助开发者在不依赖jQuery的情况下,获取DOM元素或组件的引用。

每个vue组件实例上,都包含一个$refs对象,里面存储着对应的DOM元素或组件的引用。

默认情况下,组件的$refs指向一个空对象

1. 使用ref引用DOM元素


MyRef组件

methods: { getRef() { //通过this.$refs.引用名称,可以获取到DOM元素的引用 console.log(this.$refs.myh3) //操作DOM元素,把文本颜色改为红色 this.$refs.myh3.style.color=’red’ }, }

2. 使用ref引用组件实例





methods: {
    getRef() {
        //通过this.$refs.引用名称,可以引用组件的实例
        console.log(this.$refs.counterRef)
        //引用到组件的实例之后,就可以调用组件上的methods方法
        this.$refs.counterRef.add()
    },
}

3. this.$nextTick(cb)方法

// 需求:编辑标题,编辑框自动聚焦


// 问题:“显示之后”,立刻获取焦点是不能成功的!
// 原因:Vue是异步更新DOM(提升性能)

组件的$nextTick(cb)方法,等DOM更新之后,才会触发执行此方法里的函数体。

语法:this.$nextTick(函数体)

this.$nextTick(()=>{
    this.$refs.inp.focus()
})

也就是,等组件的DOM异步地重新渲染完成之后,再执行cb回调函数。从而保证cb回调函数可以操作到最新的DOM元素。

4. resetFields

resetFields方法是Vue.js自带的重置表单方法

resetFields方法通常与表单验证和表单提交一起使用。

在表单验证失败时,将输入数据重置为初始值是一个常见的做法。resetFields方法可以快速、方便地执行此操作。

在表单提交后,需要将表单数据清空以便用户再次使用表单时能够开始一个新的会话。

vue脚手架(vue-cli),vue2,vue3,ref引用,路由和路由插件(vue-router),路由导航守卫,插槽_第9张图片

上面的代码中,使用resetFields方法将包含username和password的表单重置为初始状态。在单击Reset form按钮后,表单数据将被重置。

5. validate

Vue.validate()是Vue.js 提供的验证方法,可以方便地在Vue项目中进行表单验证。

Vue.validate()可以轻松实现对表单输入内容的验证,包括必填字段、数字、邮箱、手机号、长度限制、正则表达式等等。

同时Vue.validate()还提供了更加自定义的API接口,可以通过传入回调函数来进行特定场景的验证工作。

7. v-model原理

原理:v-model本质上是一个语法糖。例如应用在输入框上,就是value属性和input事件的合写。

作用:提供数据的双向绑定。

1. 数据变,视图跟着变:value

2. 视图变,数据跟着变@input

注意:$event用于在模板中获取事件的形参