首页 > 其他分享 >Vue 2

Vue 2

时间:2023-03-20 19:45:16浏览次数:40  
标签:Vue vue 指令 组件 router 路由

Vue 2.0

一、Vue基础入门

(一)、Vue简介

1、什么是Vue

​ 官方给出的概念:Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的前端框架。

2、Vue特性

​ vue 框架的特性,主要体现在如下两方面:

数据驱动视图
双向数据绑定

2.1 数据驱动视图

​ 在使用了 vue 的页面中,vue 会监听数据的变化,从而自动重新渲染页面的结构。示意图如下:

好处:当页面数据发生变化时,页面会自动重新渲染!
注意:数据驱动视图是单向的数据绑定。

2.2 双向数据绑定

​ 在填写表单时,双向数据绑定可以辅助开发者在不操作 DOM 的前提下,自动把用户填写的内容同步到数据源 中。示意图如下:

好处:开发者不再需要手动操作 DOM 元素,来获取表单元素最新的值!

2.3 MVVM

​ MVVM 是 vue 实现数据驱动视图和双向数据绑定的核心原理。MVVM 指的是 Model、View 和 ViewModel, 它把每个 HTML 页面都拆分成了这三个部分,如图所示:

在 MVVM 概念中:
Model 表示当前页面渲染时所依赖的数据源。
View 表示当前页面所渲染的 DOM 结构。
ViewModel 表示 vue 的实例,它是 MVVM 的核心。

2.4 MVVM 的工作原理

ViewModel 作为 MVVM 的核心,是它把当前页面的数据源(Model)页面的结构(View)连接在了一起。

​ 当数据源发生变化时,会被 ViewModel 监听到,VM 会根据最新的数据源自动更新页面的结构。
​ 当表单元素的值发生变化时,也会被 VM 监听到,VM 会把变化过后最新的值自动同步到 Model 数据源中。

3、Vue的版本

当前,vue 共有 3 个大版本,其中:
2.x 版本的 vue 是目前企业级项目开发中的主流版本
3.x 版本的 vue 于 2020-09-19 发布,生态还不完善,尚未在企业级项目开发中普及和推广
1.x 版本的 vue 几乎被淘汰,不再建议学习与使用

总结:
3.x 版本的 vue 是未来企业级项目开发的趋势;
2.x 版本的 vue 在未来(1 ~ 2年内)会被逐渐淘汰;

(二)、Vue的基本使用

1、基本使用步骤

① 导入 vue.js 的 script 脚本文件
② 在页面中声明一个将要被 vue 所控制的 DOM 区域
③ 创建 vm 实例对象(vue 实例对象)

<body>
    <!-- 2、在页面中声明一个将要被vue所控制的DOM区域 -->
    <div id="app">{{username}}</div>
    <!-- 1、导入vue.js在线开发学习版本 -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
    <script>
        // 3、创建vm实例对象(vue实例对象) 
    const vm = new Vue({
        // 3.1、指定当前vm实例要控制页面的哪个区域
        el:'#app',
        // 3.2、指定Model数据源
        data:{
            username:'zs'
        }
    })</script>
</body>

2、基本代码与MVVM的对应关系

(三)、Vue的调试工具

1、安装 vue-devtools 调试工具

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

Chrome 浏览器在线安装 vue-devtools :

https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd

FireFox 浏览器在线安装 vue-devtools : https://addons.mozilla.org/zh-CN/firefox/addon/vue-js-devtools/

2、配置 Chrome 浏览器中的 vue-devtools

点击 Chrome 浏览器右上角的 按钮,选择更多工具 -> 扩展程序 -> Vue.js devtools 详细信息,并勾选如下 的两个选项:

注意:修改完配置项,须重启浏览器才能生效!

3、使用 vue-devtools 调试 vue 页面

在浏览器中访问一个使用了 vue 的页面,打开浏览器的开发者工具,切换到 Vue 面板,即可使用 vue-devtools 调试当前的页面。

(四)、Vue的指令与过滤器

1、指令的概念

指令(Directives)是 vue 为开发者提供的模板语法,用于辅助开发者渲染页面的基本结构。

vue 中的指令按照不同的用途可以分为如下 6 大类:

内容渲染指令(v-text、{{}}、v-html...)
属性绑定指令 (v-bind)
事件绑定指令 (v-on)
双向绑定指令
条件渲染指令
列表渲染指令

注意:指令是 vue 开发中最基础、最常用、最简单的知识点。

1.1 内容渲染指令

内容渲染指令用来辅助开发者渲染 DOM 元素的文本内容。常用的内容渲染指令有如下 3 个:

  • v-text

  • {{ }}

  • v-html

v-text

用法示例:

<!-- 希望 Vue 能够控制下面的这个 div,帮我们在把数据填充到 div 内部 -->
    <div id="app">
      <p v-text="username"></p>
      <p v-text="gender">性别:</p>
    </div>

    <!-- 1. 导入 Vue 的库文件,在 window 全局就有了 Vue 这个构造函数 -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
    <!-- 2. 创建 Vue 的实例对象 -->
    <script>
      // 创建 Vue 的实例对象
      const vm = new Vue({
        // el 属性是固定的写法,表示当前 vm 实例要控制页面上的哪个区域,接收的值是一个选择器
        el: "#app",
        // data 对象就是要渲染到页面上的数据
        data: {
          username: "zhangsan",
          gender: "女",
        },
      });
    </script>

<!--数据渲染为zhangsan 女-->

注意:v-text 指令会覆盖元素内默认的值。

{{}}语法——插值表达式

vue 提供的 {{ }} 语法,专门用来解决 v-text 会覆盖默认文本内容的问题。这种 {{ }} 语法的专业名称是插值表达式(英文名为:Mustache)。

注意:相对于 v-text 指令来说,插值表达式在开发中更常用一些!因为它不会覆盖元素中默认的文本内容。

v-html

v-text 指令和插值表达式只能渲染纯文本内容。如果要把包含 HTML 标签的字符串渲染为页面的 HTML 元素, 则需要用到 v-html 这个指令:

<!-- 希望 Vue 能够控制下面的这个 div,帮我们在把数据填充到 div 内部 -->
    <div id="app">
      <div v-html="info"></div>
    </div>

    <!-- 1. 导入 Vue 的库文件,在 window 全局就有了 Vue 这个构造函数 -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
    <!-- 2. 创建 Vue 的实例对象 -->
    <script>
      // 创建 Vue 的实例对象
      const vm = new Vue({
        // el 属性是固定的写法,表示当前 vm 实例要控制页面上的哪个区域,接收的值是一个选择器
        el: "#app",
        // data 对象就是要渲染到页面上的数据
        data: {
          info: '<h4 style="color: red; font-weight: bold;">欢迎大家来学习 vue.js</h4>',
        },
      });
    </script>
欢迎大家来学习VUe.js
1.2 属性绑定指令

如果需要为元素的属性动态绑定属性值,则需要用到 v-bind 属性绑定指令。用法示例如下:

属性绑定指令的简写形式

由于 v-bind 指令在开发中使用频率非常高,因此,vue 官方为其提供了简写形式(简写为英文的 : )

使用 Javascript 表达式

在 vue 提供的模板渲染语法中,除了支持绑定简单的数据值之外,还支持 Javascript 表达式的运算,例如:

1.3、事件绑定指令

vue 提供了 v-on 事件绑定指令,用来辅助程序员为 DOM 元素绑定事件监听。语法格式如下:

<h3>count的值为:{{count}}</h3>
<!-- 语法格式为v-on:事件名称=“事件处理函数的名称”-->
<button v-on:click="addCount">+1</button>

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

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

const vm = new Vue({
	el:'#app',
	data:{ count:0 },
	methods:{	// v-on绑定的事件处理函数,需要声明在methods节点中
		addCount(){  //事件处理函数的名字
            // this表示当前new出来的vm实例对象
            // 通过this可以访问到data中的数据
			this.count +=1
	}}
})

事件绑定的简写形式

由于 v-on 指令在开发中使用频率非常高,因此,vue 官方为其提供了简写形式(简写为英文的@)。

事件参数对象

在原生的 DOM 事件绑定中,可以在事件处理函数的形参处,接收事件参数对象 event。同理,在 v-on 指令(简写为 @ )所绑定的事件处理函数中,同样可以接收到事件参数对象 event,示例代码如下:

绑定事件并传参

在使用 v-on 指令绑定事件时,可以使用 ( ) 进行传参,示例代码如下:

<h3>count的值为:{{count}}</h3>
<button @click="addNewCount(2)">+2</button>
---------------------分割线--------------------
methods:{
	// 在形参处用step接收传递过来的参数值
	addNewCount(step){
	this.count += step
}
}

$event

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

<h3>count的值为:{{count}}</h3>
<button @click="addNewCount(2,$event)">+2</button>
---------------------分割线---------------------------
 methods:{
     addNewCount(step,e){
	const nowBgColor = e.target.style.backgroundColor
	e.target.style.backgroundColor = nowBgColor === 'cyan' ? '' : 'cyan'
	this.count += step
}
 }

事件修饰符

在事件处理函数中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。因此, vue 提供了事件修饰符的概念,来辅助程序员更方便的对事件的触发进行控制。常用的 5 个事件修饰符如下:

语法格式如下:

<!--触发click点击事件时,阻止a链接的默认跳转行为-->
<a href="httpS://www.baidu.com" @click.prevent="onLinkClick">百度首页</a>

按键修饰符

在监听键盘事件时,我们经常需要判断详细的按键。此时,可以为键盘相关的事件添加按键修饰符,例如:

<!--只有在'key'是'Enter'时调用'vm.submit()'-->
<input @keyup.eenter="submit">
<!--只有在'key'是'Esc'时调用'vm.clearInput()'-->
<input @keyup.esc="clearInput">
1.4 双向绑定指令

vue 提供了 v-model 双向数据绑定指令,用来辅助开发者在不操作 DOM 的前提下,快速获取表单的数据

<p>用户名是:{{username}}</p>
<input type="text" v-model="username" />
<p>选中的省份是:{{province}}</p>
<select v-model="province">
    <option value="">请选择</option>
    <option value="1">北京</option>
    <option value="2">河北</option>
    <option value="3">黑龙江</option>
</select>

v-model 指令的修饰符

为了方便对用户输入的内容进行处理,vue 为 v-model 指令提供了 3 个修饰符,分别是:

示例用法如下:

<input type="text" v-model.number="n1">+
<input typr="text" v-model.number="n2">=
<span>{{n1+n2}}</span>
1.5 条件渲染指令

条件渲染指令用来辅助开发者按需控制 DOM 的显示与隐藏。条件渲染指令有如下两个,分别是:

  • v-if
  • v-show

示例用法如下:

<div id="app">
    <p v-if="networkState === 200">请求成功 ---被v-if控制</p>
    <p v-show="networkState === 200">请求成功 ---被v-show控制</p>
</div>

v-if 和 v-show 的区别

实现原理不同:

  • v-if 指令会动态地创建或移除 DOM 元素,从而控制元素在页面上的显示与隐藏;

  • v-show 指令会动态为元素添加或移除 style= "display: none;" 样式,从而控制元素的显示与隐藏;

性能消耗不同:

v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此:

  • 如果需要非常频繁地切换,则使用 v-show 较好

  • 如果在运行时条件很少改变,则使用 v-if 较好

v-else

v-if 可以单独使用,或配合 v-else 指令一起使用:

<div v-if="Math.random() > 0.5">
    随机数大于0.5
</div>
<div v-else>
    随机数小于或等于0.5
</div>

注意:v-else 指令必须配合 v-if 指令一起使用,否则它将不会被识别!

v-else-if

v-else-if 指令,顾名思义,充当 v-if 的“else-if 块”,可以连续使用:

<div v-if="type === A">优秀</div>
<div v-else-if="type === B">良好</div>
<div v-else-if="type === C">一般</div>
<div v-else>差</div>

注意:v-else-if 指令必须配合 v-if 指令一起使用,否则它将不会被识别!

1.6 列表渲染指令

vue 提供了 v-for 列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。v-for 指令需要使 用 item in items 形式的特殊语法,其中:

  • items 是待循环的数组

  • item 是被循环的每一项

data:{
	list:[	// 列表数据
	{id:1,name:'zs'},
	{id:2,name:'ls'}
	]
}
-----------------分割线-----------------------
<ul>
    <li v-for="item in list">姓名是:{{item.name}}</li>
</ul>

v-for 中的索引

v-for 指令还支持一个可选的第二个参数,即当前项的索引。语法格式为 (item, index) in items,示例代码如下:

data:{
	list:[	// 列表数据
	{id:1,name:'zs'},
	{id:2,name:'ls'}
	]
}
-----------------分割线-----------------------
<ul>
    <li v-for="(item,index) in list">索引是:{{index}},姓名是:{{item.name}}</li>
</ul>

注意:v-for 指令中的 item 项和 index 索引都是形参,可以根据需要进行重命名。例如 (user, i) in userlist

使用 key 维护列表的状态

​ 当列表的数据变化时,默认情况下,vue 会尽可能的复用已存在的 DOM 元素,从而提升渲染的性能。但这种 默认的性能优化策略,会导致有状态的列表无法被正确更新。 为了给 vue 一个提示,以便它能跟踪每个节点的身份,从而在保证有状态的列表被正确更新的前提下,提升渲 染的性能。此时,需要为每项提供一个唯一的 key 属性

<ul>
  <!--加key属性的好处-->
    <!--1、正确维护列表的状态-->
    <!--2、复用现有的DOM元素,提升渲染的性能-->
    <li v-for="user in userList" :key="user.id">
    <input type="checkbox" />
        姓名:{{user.name}}
    </li>
</ul>

key 的注意事项

① key 的值只能是字符串或数字类型
② key 的值必须具有唯一性(即:key 的值不能重复)
③ 建议把数据项 id 属性的值作为 key 的值(因为 id 属性的值具有唯一性)
④ 使用 index 的值当作 key 的值没有任何意义(因为 index 的值不具有唯一性)
⑤ 建议使用 v-for 指令时一定要指定 key 的值(既提升性能、又防止列表状态紊乱)

2、过滤器

过滤器(Filters)是 vue 为开发者提供的功能,常用于文本的格式化。过滤器可以用在两个地方:插值表达式v-bind 属性绑定
​ 过滤器应该被添加在 JavaScript 表达式的尾部,由“管道符”进行调用,示例代码如下:

<!--在双花括号中通过“管道符”调用capitalize过滤器,对message的值进行格式化-->
<p>{{message | capitalize}}</p>
<!--在 v-bind中通过“管道符”调用formatId过滤器,对rawId的值进行格式化-->
<div v-bind:id="rawId | formatId"></div>
2.1 定义过滤器

在创建 vue 实例期间,可以在 filters 节点中定义过滤器,示例代码如下:

const vm = new Vue({
    el:'#app',
    data:{
        message:'hello vue.js',
        info:'title info'
    },
    filters:{  // 在filters节点下定义"过滤器"
        capitalize(str){  // 把首字母转为大写的过滤器
            return str.charAt(0).toUpperCase() + str.slice(1)
        }
    }
})
2.2 私有过滤器和全局过滤器

在 filters 节点下定义的过滤器,称为“私有过滤器”,因为它只能在当前 vm 实例所控制的 el 区域内使用。 如果希望在多个 vue 实例之间共享过滤器,则可以按照如下的格式定义全局过滤器

// 全局过滤器 - 独立于每个vm实例之外
// Vue.filter()方法接收两个参数
// 第1个参数,是全局过滤器的“名字”
// 第2个参数,是全局过滤器的“处理函数”
Vue.filter('capitalize',(str) => {
    return str.charAt(0).toUpperCase() + str.slice(1) + '~~'
})
2.3连续调用多个过滤器

过滤器可以串联地进行调用,例如:

<!--把message的值,交给filterA进行处理-->
<!--把filterA处理的结果,再交给filter进行处理-->
<!--最终把filterB处理的结果,作为最终的值渲染到页面上-->
{{message | filterA | filterB}}

实例代码如下:

<!--串联调用多个过滤器-->
<p>{{text | capitalize | maxLength}}</p>

// 全局过滤器-首字母大写
Vue.filter('capitalize',(str) => {
	return str.charAt(0).toUpperCase() + str.slice(1) + '--'
})

// 全局过滤器--控制文本的最大长度
Vue.filter('maxLength',(str) => {
	if(str.length <= 10) return str
     return str.slice(0,11)+'...'
})
2.4 过滤器传参

过滤器的本质是 JavaScript 函数,因此可以接收参数,格式如下:

<!--arg1 和 arg2是传递给filterA的参数-->
<p>{{ message | filter(arg1,arg2) }}</p>

// 过滤器处理函数的形参列表中:
// 第一个参数:永远都是“管道符”前面待处理的值
// 从第二个参数开始,才是调用过滤器时传递过来的arg1 和 arg2参数
Vue.filter('filterA',(msg,arg1,arg2) => {
    // 过滤器的代码逻辑...
})

示例代码如下:

<!--调用maxLength 过滤器时传参-->
<p>{{text | capitalize | maxLength(5)}}</p>

// 全局过滤器-首字母大写
Vue.filter('capitalize',(str) => {
	return str.charAt(0).toUpperCase() + str.slice(1) + '--'
})

// 全局过滤器--控制文本的最大长度
Vue.filter('maxLength',(str,len = 10) => {
	if(str.length <= len) return str
     return str.slice(0,len)+'...'
})
2.5 过滤器的兼容性

过滤器仅在 vue 2.x 和 1.x 中受支持,在 vue 3.x 的版本中剔除了过滤器相关的功能。 在企业级项目开发中:

  • 如果使用的是 2.x 版本的 vue,则依然可以使用过滤器相关的功能

  • 如果项目已经升级到了 3.x 版本的 vue,官方建议使用计算属性方法代替被剔除的过滤器功能

具体的迁移指南,请参考 vue 3.x 的官方文档给出的说明: https://v3.vuejs.org/guide/migration/filters.html#migration-strategy

(五)、品牌列表案例

1、案例效果

2、整体实现步骤

① 创建基本的 vue 实例
② 基于 vue 渲染表格数据
③ 实现添加品牌的功能
④ 实现删除品牌的功能
⑤ 实现修改品牌状态的功能

(六)、侦听器(watch)

1、什么是watch侦听器

watch 侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作。 语法格式如下:

const vm = new Vue({
    el:'#app',
    data:{username:''},
    watch:{
        // 监听username值的变化
        // newVal是"变化后的新值",oldVal是"变化之前的旧值"
        username(newVal,oldVal){
            console.log(newVal,oldVal)
        }
    }
})

2、使用 watch 检测用户名是否可用

监听 username 值的变化,并使用 axios 发起 Ajax 请求,检测当前输入的用户名是否可用

watch: { 		
    //监听 username值的变化
    async username(newVal) {if (newVal === '') return
    //使用 axios发起请求,判断用户名是否可用
    const { data: res } = await axios.get('https://www.escook.cn/api/finduser/' + newVal)
    console.log(res)
   }
}

3、immediate 选项

默认情况下,组件在初次加载完毕后不会调用 watch 侦听器。如果想让 watch 侦听器立即被调用,则需要使 用 immediate 选项。示例代码如下:

watch: {
	username: {	
	// handler 是固定写法,表示当 username 的值变化时,自动调用 handler 处理函数
	handler: async function (newVal) {
		if (newVal === '') return
		const { data: res } = await axios.get('https://www.escook.cn/api/finduser/' + newVal)
		console.log(res)
	},
	// 表示页面初次渲染好之后,就立即触发当前的 watch 侦听器
		immediate: true
	}
}

4、deep 选项

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

const vm = new Vue({
    el:'#app',
    data:{
        info:{username:'admin'}
    },
    watch:{
        info:{
            handler(newVal){
                console.log(newVal,username)
            },
            deep:true
        }
    }
})

5、监听对象单个属性的变化

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

const vm = new Vue({
	el:'#app',
    data:{
        info:{username:'admin'}
    },
    watch:{
        'info.username':{
            handler(newVal){
                console.log(newVal)
            }
        }
    }
})

(七)、计算属性(computed)

1、什么是计算属性

计算属性指的是通过一系列运算之后,最终得到一个属性值
这个动态计算出来的属性值可以被模板结构或 methods 方法使用。示例代码如下:

var vm = new Vue({
    el:'#app',
    data:{
        r:0, g:0, b:0
    },
    computed:{
        rgb(){ return 'rgb($(this.r), $(this.g), $(this.b))' }
    },
    methods:{
        show(){ console.log(this.rgb) }
    }
})

2、计算属性的特点

① 虽然计算属性在声明的时候被定义为方法,但是计算属性的本质是一个属性
② 计算属性会缓存计算的结果,只有计算属性依赖的数据变化时,才会重新进行运算

(八)、vue-cli

1、什么是单页面应用程序

单页面应用程序(英文名:Single Page Application)简称 SPA,顾名思义,指的是一个 Web 网站中只有唯一的一个 HTML 页面,所有的功能与交互都在这唯一的一个页面内完成。

2、什么是 vue-cli

vue-cli 是 Vue.js 开发的标准工具。它简化了程序员基于 webpack 创建工程化的 Vue 项目的过程。
引用自 vue-cli 官网上的一句话:
程序员可以专注在撰写应用上,而不必花好几天去纠结 webpack 配置的问题。

中文官网:https://cli.vuejs.org/zh/

3、安装和使用

vue-cli 是 npm 上的一个全局包,使用 npm install 命令,即可方便的把它安装到自己的电脑上:
npm install -g @vue/cli

基于 vue-cli 快速生成工程化的 Vue 项目:
vue create 项目的名称

4、vue 项目的运行流程

在工程化的项目中,vue 要做的事情很单纯:通过 main.jsApp.vue 渲染到 index.html 的指定区域中。

其中:
App.vue 用来编写待渲染的模板结构
index.html 中需要预留一个 el 区域
main.js 把 App.vue 渲染到了 index.html 所预留的区域中

(九)、vue组件

1、什么是组件化开发

组件化开发指的是:根据封装的思想,把页面上可重用的 UI 结构封装为组件,从而方便项目的开发和维护。

2、vue 中的组件化开发

vue 是一个支持组件化开发的前端框架。 vue 中规定:组件的后缀名.vue。之前接触到的 App.vue 文件本质上就是一个 vue 的组件。

3、vue 组件的三个组成部分

每个 .vue 组件都由 3 部分构成,分别是:

  • template -> 组件的模板结构

  • script -> 组件的 JavaScript 行为

  • style -> 组件的样式

其中,每个组件中必须包含 template 模板结构,而 script 行为style 样式可选的组成部分。

3.1 template

vue 规定:每个组件对应的模板结构,需要定义到 < template > 节点中。

<template>
    <!--当前组件的DOM结构,需要定义到template标签的内部-->
</template>

注意:

  • template 是 vue 提供的容器标签,只起到包裹性质的作用,它不会被渲染为真正的 DOM 元素

  • template 中只能包含唯一的根节点

3.2 script

vue 规定:开发者可以在 < script >节点中封装组件的javaScript业务逻辑
< script >节点的基本结构如下:

<script>
 // 今后,组件相关的data数据,methods方法等,都需要定义到export default所导出的对象中
    export defalut{}
</script>

.vue 组件中的 data 必须是函数

vue 规定:.vue 组件中的 data 必须是一个函数不能直接指向一个数据对象。 因此在组件中定义 data 数据节点时,下面的方式是错误的:

data:{ // 组件中,不能直接让data指向一个数据对象(会报错)
	count: 0	
}

会导致多个组件实例共用同一份数据的问题,请参考官方给出的示例:
https://cn.vuejs.org/v2/guide/components.html#data-必须是一个函数

3.3 style

vue 规定:组件内的 < style >节点是可选的,开发者可以在 < style >节点中编写样式美化当前组件的UI结构。

< script >节点的基本结构如下:

在< style >标签上添加 lang= "less" 属性,即可使用 less 语法编写组件的样式:

<style scoped lang="less">
     <!--scoped 当前组件样式生效,css语法的其中一种--> 
    h1{
        font-weight: normal;
        span{
            color:red;
        }
    }
</style>

4、组件之间的父子关系

组件在被封装好之后,彼此之间是相互独立的,不存在父子关系
使用组件的时候,根据彼此的嵌套关系,形成了父子关系、兄弟关系

4.1 使用组件的三个步骤

步骤1:使用import语法导入需要的组件

import Left from '@/components/Left.vue'

步骤2:使用components节点注册组件

export default {
    components: {
        Left
    }
}

步骤3:以标签形式使用刚才注册的组件

<div class="box">
    <Left></Left>
</div>
4.2 通过 components 注册的是私有子组件

例如: 在组件 A 的 components 节点下,注册了组件 F。
则组件 F 只能用在组件 A 中;不能被用在组件 C 中。

请大家思考两个问题:
① 为什么 F 不能用在组件 C 中?
② 怎样才能在组件 C 中使用 F?

4.3 注册全局组件

在 vue 项目的 main.js 入口文件中,通过 Vue.component() 方法,可以注册全局组件。示例代码如下:

// 导入需要全局注册的组件
import Count from '@/components/Count.vue'

// 参数1:字符串格式,表示组件的“注册名称”
// 参数2:需要被全局注册的那个组件
Vue.component('MyCount',Count)

5、组件的 props

props 是组件的自定义属性,在封装通用组件的时候,合理地使用 props 可以极大的提高组件的复用性! 它的语法格式如下:

export default {
    // 组件的自定义属性
    props:['自定义属性A','自定义属性B','其它自定义属性...'],
    
// 组件的私有数据
    data() {
        return{}
    }
}
5.1 props 是只读的

vue 规定:组件中封装的自定义属性是只读的,程序员不能直接修改 props 的值。否则会直接报错:

要想修改 props 的值,可以把 props 的值转存到 data 中,因为 data 中的数据都是可读可写的!

props:['init'],
data() {
    return {
        // 把this.init的值转存到count
        count:this.init
    }
}
5.2 props 的 default 默认值

在声明自定义属性时,可以通过 default定义属性的默认值。示例代码如下:

export default {
    props:{
        init:{
            //用default 属性定义属性的默认值
            default:0
        }
    }
}
5.3 props 的 type 值类型

在声明自定义属性时,可以通过 type定义属性的值类型。示例代码如下:

export default {
    props:{
        init:{
            //用default 属性定义属性的默认值
            default:0,
            // 用type属性定义属性的值类型
            // 如果传递过来的值不符合此类型,则会在终端报错
            type: Number
        }
    }
}
5.4 props 的 required 必填项

在声明自定义属性时,可以通过 required 选项,将属性设置为必填项,强制用户必须传递属性的值。示例代 码如下:

export default {
    props:{
        init:{
		//值类型为Number数字
           type: Number,
            // 必填项校验
            required:true
        }
    }
}

6、组件之间的样式冲突问题

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

导致组件之间样式冲突的根本原因是:
① 单页面应用程序中,所有组件的 DOM 结构,都是基于唯一的 index.html 页面进行呈现的
② 每个组件中的样式,都会影响整个 index.html 页面中的 DOM 元素

6.1 思考:如何解决组件样式冲突的问题

为每个组件分配唯一的自定义属性,在编写组件样式时,通过属性选择器来控制样式的作用域,示例代码如下:

<template>
<div class="container" data-v-001>
    <h3 data-v-001>轮播图组件</h3>
    </div>
</template>
<style>
<!--通过中括号“属性选择器”,来防止组件之间的“样式冲突问题”,因为每个组件分配的自定义属性是“唯一的”-->
    .container[data-v-001] {
        border:1px solid red;
    }
</style>
6.2 style 节点的 scoped 属性

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

<template>
<div class="container">
    <h3>轮播图组件</h3>
    </div>
</template>
<style scoped>
<!--style 节点的scoped属性,用来自动为每个组件分配唯一的“自定义属性”,并自动为当前组件的DOM标签和style样式应用这个自定义属性,防止组件的样式冲突问题-->
.container{
    border:1px solid red;
    }
</style>

6.3 /deep/ 样式穿透

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

<style lang="less" scoped>
    .title{
        color:blue; /*不加/deep/时,生成的选择器格式为 .title[data-v-052242de]*/
    }
    /deep/ .title{
        color:blue;/*加上/deep/时,生成的选择器格式为[data-v-052242de] .title*/
    }
</style>

二、生命周期&数据共享

(一)、组件的生命周期

1、生命周期&生命周期函数

生命周期(Life Cycle)是指一个组件从创建 -> 运行 -> 销毁的整个阶段,强调的是一个时间段
生命周期函数:是由 vue 框架提供的内置函数,会伴随着组件的生命周期,自动按次序执行

注意:生命周期强调的是时间段生命周期函数强调的是时间点。

2、组件生命周期函数的分类

3、生命周期图示

可以参考 vue 官方文档给出的“生命周期图示”,进一步理解组件生命周期执行的过程:

https://cn.vuejs.org/v2/guide/instance.html#生命周期图示

(二)、组件之间的数据共享

1、组件之间的关系

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

① 父子关系
② 兄弟关系

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

父子组件之间的数据共享又分为:
① 父 -> 子共享数据
② 子 -> 父共享数据

2.1 父组件向子组件共享数据

父组件向子组件共享数据需要使用自定义属性。示例代码如下:

// 父组件
<Son :msg="message" :user="userinfo"></Son>

data(){
    return {
        message:'hello vue.js',
        userinfo: {name:'zs',age:20}
    }
}
// 子组件
<template>
<div>
    <h5>Son组件</h5>
	<p>父组件传递过来的msg是:{{msg}}</p>
	<p>父组件传递过来的user是:{{user}}</p>
</div>
</template>
// 接收父组件传过来的数据
props:['msg','user']
2.2 子组件向父组件共享数据

子组件向父组件共享数据使用自定义事件。示例代码如下:

// 子组件
export default {
    data() {
        return {count:0}
    },
    methods:{
        add() {
            this.count += 1
            // 修改数据时,通过$emit()触发自定义事件
            this.$emit('numchange',this.count)
        }
    }
}
// 父组件
// 接收子组件传过来的数据
<Son @numchange="getNewCount"></Son>

export default {
    data() {
        return {countFromSon: 0}
    },
    methods:{
        getNewCount(var) {
            this.countFromSon = val
        }
    }
}

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

vue2.x 中,兄弟组件之间数据共享的方案是 EventBus。

// 兄弟组件A(数据发送方)
import bus from './eventBus.js’

export default {
	data() {
		return {
			msg: 'hello vue.js'
		}
	},
	methods: {
		sendMsg() {
            // 把数据传输给eventBus.js
			bus.$emit('share', this.msg)
		}
	}
}
// eventBus.js
import Vue from 'vue'

// 向外共享 Vue 的实例对象
export default new Vue()
// 兄弟组件C(数据接收方)
import bus from './eventBus.js'

export default {
	data() {
		return {
			msgFromLeft: ''
		}
	},
	created() {
        // 从eventBus.js拿到传输过来的数据
		bus.$on('share', val => {
			this.msgFromLeft = val
		})
	}
}

EventBus 的使用步骤

① 创建 eventBus.js 模块,并向外共享一个 Vue 的实例对象

② 在数据发送方,调用 bus.$emit('事件名称', 要发送的数据) 方法触发自定义事件

③ 在数据接收方,调用 bus.$on('事件名称', 事件处理函数) 方法注册一个自定义事件

(三)、ref引用

1、什么是 ref 引用

ref 用来辅助开发者在不依赖于 jQuery 的情况下,获取 DOM 元素或组件的引用。 每个 vue 的组件实例上,都包含一个 $refs 对象,里面存储着对应的 DOM 元素或组件的引用。默认情况下,

组件的 $refs 指向一个空对象。

<template>
    <div>
    <h3>MyRef组件</h3>
	<button @click="getRef">获取 $refs引用</button>
    </div>
</template>

export default {
    methods:{
        getRef() {
            console.log(this) // this是当前组件的实例对象,this.$refs 默认指向空对象
        }
    }
}

2、使用 ref 引用 DOM 元素

如果想要使用 ref 引用页面上的 DOM 元素,则可以按照如下的方式进行操作:

<!--使用ref属性,为对应的DOM添加引用名称-->
<h3 ref="myh3">MyRef组件</h3>
<button @click="getRef">获取$refs 引用</button>

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

3、使用 ref 引用组件实例

如果想要使用 ref 引用页面上的组件实例,则可以按照如下的方式进行操作:

!--使用ref属性,为对应的“组件”添加引用名称-->
<my-counter ref-"counterRef"></my-counter>
<button @click="getRef">获取$refs 引用</button>

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

4、控制文本框和按钮的按需切换

通过布尔值 inputVisible 来控制组件中的文本框与按钮的按需切换。示例代码如下:

<template>
	<input type="text" v-if="inputVisble">
    <button v-else @click="showInput">展示input输入框</button>
</template>
<script>
    export default {
		data() {
            return {
                // 控制文本框和按钮的按需切换
                inputVisible:false
            }
        },
            methods:{
                showInput() { //切换布尔值,显示文本框
                    this.inputVisible = true
                }
            }
}
 </script>

5、让文本框自动获得焦点

当文本框展示出来之后,如果希望它立即获得焦点,则可以为其添加 ref 引用,并调用原生 DOM 对象的

.focus() 方法即可。示例代码如下:

<input type="text" v-if="inputVisible" ref="ipt">
<button v-else @click="showInput">显示input输入框</button>

methods:{
	showInput() {
		this.inputVisible = true
		//获取文本框的DOM引用,并调用.focus()使其自动获得焦点
		this.$refs.ipt.focus()
}
}

6、this.$nextTick(cb) 方法

组件的 $nextTick(cb) 方法,会把 cb 回调推迟到下一个 DOM 更新周期之后执行。通俗的理解是:等组件的 DOM 更新完成之后,再执行 cb 回调函数。从而能保证 cb 回调函数可以操作到最新的 DOM 元素。

<input type="text" v-if="inputVisible" ref="ipt">
<button v-else @click="showInput">显示input输入框</button>

methods:{
	showInput() {
		this.inputVisible = true
		// 把对input 文本框的操作,推迟到下次DOM更新之后,否则页面上根本不存在文本框元素
		this.$nextTick() => {
            this.$ref.ipt.focus()
        }
}
}

(四)、购物车案例

1、实现步骤

① 初始化项目基本结构
② 封装 MyHeader 组件
③ 基于 axios 请求商品列表数据( GET 请求,地址为 https://www.escook.cn/api/cart
④ 封装 MyFooter 组件
⑤ 封装 MyGoods 组件
⑥ 封装 MyCounter 组件

三、动态组件 & 插槽 & 自定义指令

(一)、动态组件

1、什么是动态组件

动态组件指的是动态切换组件的显示与隐藏。

2、如何实现动态组件渲染

vue 提供了一个内置的< component > 组件,专门用来实现动态组件的渲染。示例代码如下:

data() {
	//1、当前要渲染的组件名称
	return {comName:'Left'}
}

<!-- 2、通过is属性,动态指定要渲染的组件-->
<component :is="comName"></component>

<!--3、点击按钮,动态切换组件的名称-->
<button @click="comName" = 'Left'>展示Left组件</button>
<button @click="comName" = 'Right'>展示Right组件</button>

3、使用 keep-alive 保持状态

默认情况下,切换动态组件时无法保持组件的状态。此时可以使用 vue 内置的 组件保持动态组 件的状态。示例代码如下:

<keep-alive>
	<component :is="comName"></component>
</keep-alive>

4、keep-alive 对应的生命周期函数

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

export default {
    created() {console.log('组件被创建了')},
    destroyed() { console.log('组件被销毁了') },
    
    activated() {console.log('Left 组件被激活了')},
    deactivated() { console.log('Left 组件被缓存了')}
}

5、keep-alive 的 include 属性

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

<keep-alive include="MyLeft,MyRight">
	<component :is='comName'></component>
</keep-alive>

(二)、插槽

1、什么是插槽

插槽(Slot)是 vue 为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望由用户指定的部分定义为插槽。

可以把插槽认为是组件封装期间,为用户预留的内容的占位符。

2、体验插槽的基础用法

在封装组件时,可以通过< slot >元素定义插槽,从而为用户预留内容占位符。示例代码如下:

<template>
<p> 这是MyCom1组件的第1个p标签</p>
    <!--通过slot标签,为用户预留内容占位符(插槽)-->
    <slot></slot>
 <p>这是MyCom1组件最后一个p标签</p>
</template>
<my-com-1>
<!--在使用MyCom1组件时,为插槽指定具体的内容-->
    <p>--用户自定义的内容----</p>
</my-com-1>
2.1 没有预留插槽的内容会被丢弃

如果在封装组件时没有预留任何< solt > 插槽,则用户提供的任何自定义内容都会被丢弃。示例代码如下:

<template>
<p> 这是MyCom1组件的第1个p标签</p>
    <!--封装组件时,没有预留任何插槽-->
 <p>这是MyCom1组件最后一个p标签</p>
</template>
my-com-1>
<!--自定义的内容会被丢弃-->
    <p>--用户自定义的内容----</p>
</my-com-1>
2.2 后备内容

封装组件时,可以为预留的 插槽提供后备内容(默认内容)。如果组件的使用者没有为插槽提供任何 内容,则后备内容会生效。示例代码如下:

<template>
<p> 这是MyCom1组件的第1个p标签</p>
    <solt>这是后备内容</solt>
 <p>这是MyCom1组件最后一个p标签</p>
</template>

3、具名插槽

如果在封装组件时需要预留多个插槽节点,则需要为每个< solt > 插槽指定具体的 name 名称。这种带有具体< solt > 名称的插槽叫做“具名插槽”。示例代码如下:

<div class="container">
    <header>
    <!--我们希望把页头放这里-->
        <solt name="header"></solt>
    </header>
    <main>
        <!--我们希望把主要内容放这里-->
        <solt></solt>
    </main>
    <footer>
    <!--我们希望把页脚放这里-->
        <solt name="footer"></solt>
    </footer>
</div>

注意:没有指定 name 名称的插槽,会有隐含的名称叫做 “default”

3.1 为具名插槽提供内容

在向具名插槽提供内容的时候,我们可以在一个< template > 元素上使用 v-slot 指令,并以 v-slot 的参数的 形式提供其名称。示例代码如下:

<my-com-2>
	<template v-slot:header>
    <h1>滕王阁序</h1>
    </template>

<template v-slot:default>
	<p>豫章故郡,洪都新府</p>
    <p>星分翼轸,地接衡庐</p>
    <p>襟三江而带五湖,控蛮荆而引瓯越</p>
</template>

<template v-slot:footer>
	<p>落款:王勃</p>
</template>
    </my-com-2>

3.2 具名插槽的简写形式

跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot

标签:Vue,vue,指令,组件,router,路由
From: https://www.cnblogs.com/hongkun2412972165/p/17237460.html

相关文章

  • vue2 - 好用的markdown开源编辑器
    mavonEditor:https://github.com/hinesboy/mavonEditor VueQuillEditor:https://www.kancloud.cn/liuwave/quill/1434140//main.js使用markdown插件importVueQuillEd......
  • Vue3+element-plus图片上传剪裁组件
    userAvatar.vue<template><divclass="user-info-head"@click="editCropper()"><img:src="options.img"title="点击上传头像"class="img-circleimg-lg"/>......
  • vue3 v-model取代vue2 .sync(个人使用记录)
    例子:封装el-pagination组件<scriptlang="ts"setup>import{computed}from"vue";constemit=defineEmits<{(e:'update:pageSize',pageSize:number):void//p......
  • Vue.js TodoList案例-编辑& $nextTick
    编辑部分功能视频$nextTick视频本节遗留问题,点击input框才有焦点,写逻辑的时候是绑定在blur上面的。如果不点击input再点击其他地方,不能触发input框转换到文字的逻辑。......
  • Vue 长文本自动隐藏和单选框默认选择
      末尾加show-tooltip-when-overflow 单选框label前加:<el-form-itemlabel="代理机构状态"><el-radio-groupv-model="form.agentstatus"><el-radio:label=......
  • vue上传图片
    <divclass="row-center"><divclass="Default-avatarcuractive"@click="setAvater"><img:src="userInfo.avatar||......
  • vue-json-viewer 展示json数据
    main.jsimportJsonViewerfrom'vue-json-viewer'Vue.use(JsonViewer);vue<el-dialogtitle="退款数据详情":visible.sync="dialogvisible2"v-if="dialogvisible......
  • vue的从0到1搭建 p3
    参考文档:https://blog.csdn.net/bai_shuang/article/details/122984811参考文档:https://blog.csdn.net/weixin_55662333/article/details/1207585834、使用less依赖1)安装l......
  • Vue.js TodoList案例pubsub
    视频MyItem.vueApp.vue修改componentsMyFooter.vue<template> <divclass="todo-footer"v-show="total"> <label> <!--<inputtype="checkbox":checked="i......
  • Vue 项目打包 部署 运行
    Vue项目打包部署运行 1、安装vuenpminstallvue 查看vue版本vue-V 2、安装cnpmnpminstall-gcnpm-registry=https://registry.npm.taobao.o......