
Vue核心 绑定样式 条件渲染
1.绑定样式
class样式
写法: :class="xxx" ,xxx 可以是字符串、数组、对象
:style="[a,b]" 其中a、b是样式对象
:style="{fontSize: xxx}" 其中 xxx 是动态值
字符串写法适用于:类名不确定,要动态获取
数组写法适用于:要绑定多个样式,个数不确定,名字也不确定
对象写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用
<style>
.basic {width: 300px;height: 50px;border: 1px solid black;}
.happy {border: 3px solid red;background-color: rgba(255, 255, 0, 0.644);
background: linear-gradient(30deg, yellow, pink, orange, yellow);}
.sad {border: 4px dashed rgb(2, 197, 2);background-color: skyblue;}
.normal {background-color: #bfa;}
.baiye1 {background-color: yellowgreen;}
.baiye2 {font-size: 20px;text-shadow: 2px 2px 10px red;}
.baiye3 {border-radius: 20px;}
</style>
<div id="root">
<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
<div class="basic" :class="mood" @click="changeMood">{{name}}</div><br/><br/>
<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
<div class="basic" :class="classArr">{{name}}</div><br/><br/>
<!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
<div class="basic" :class="classObj">{{name}}</div><br/><br/>
<!-- 绑定style样式--对象写法 -->
<div class="basic" :style="styleObj">{{name}}</div><br/><br/>
<!-- 绑定style样式--数组写法 -->
<div class="basic" :style="styleArr">{{name}}</div>
</div>2. 条件渲染
v-if
写法 跟 if else 语法类似
v-if="表达式"
v-else-if="表达式"
v-else
适用于:切换频率较低的场景,因为不展示的 DOM 元素直接被移除
注意: v-if 可以和 v-else-if v-else 一起使用,但要求结构不能被打断
v-show
写法: v-show="表达式"
适用于:切换频率较高的场景
特点:不展示的 DOM 元素未被移除,仅仅是使用样式隐藏掉 display: none
备注:使用 v-if 的时,元素可能无法获取到,而使用 v-show 一定可以获取到
template 标签不影响结构,页面 html 中不会有此标签,但只能配合 v-if ,不能配合 v-show
3.列表渲染
v-for 指令
用于展示列表数据
语法: <li v-for="(item, index) of items" :key="index"> ,这里 key 可以是 index ,更好的是遍历对象的唯一标识
可遍历:数组、对象、字符串(用的少)、指定次数(用的少)
<title>基本列表</title>
<script type="text/javascript" src="../js/vue.js"></script>
<div id="root">
<!-- 遍历数组 -->
<h3>人员列表(遍历数组)</h3>
<ul>
<li v-for="(p,index) of persons" :key="index">{{ p.name }}-{{ p.age }}</li>
</ul>
<!-- 遍历对象 -->
<h3>汽车信息(遍历对象)</h3>
<ul>
<li v-for="(value,k) of car" :key="k">{{ k }}-{{ value }}</li>
</ul>
<!-- 遍历字符串 -->
<h3>测试遍历字符串(用得少)</h3>
<ul>
<li v-for="(char,index) of str" :key="index">{{ char }}-{{ index }}</li>
</ul>
<!-- 遍历指定次数 -->
<h3>测试遍历指定次数(用得少)</h3>
<ul>
<li v-for="(number,index) of 5" :key="index">{{ index }}-{{ number }}</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false
new Vue({
el: '#root',
data: {
persons: [
{ id: '001', name: '张三', age: 18 },
{ id: '002', name: '李四', age: 19 },
{ id: '003', name: '王五', age: 20 }
],
car: {
name: '奥迪A8',
price: '70万',
color: '黑色'
},
str: 'hello'
}
})
</script>
面试题: react vue 中的 key 有什么作用?( key 的内部原理)
- 虚拟DOM 中 key 的作用: key 是 虚拟DOM 中对象的标识,当数据发生变化时, Vue 会根据新数据生成新的 虚拟DOM ,随后 Vue 进行新 虚拟DOM 与旧 虚拟DOM 的差异比较,比较规则如下
- 对比规则
a. 旧 虚拟DOM 中找到了与新 虚拟DOM 相同的 key
ⅰ. 若 虚拟DOM 中内容没变, 直接使用之前的 真实DOM
ⅱ. 若 虚拟DOM 中内容变了, 则生成新的 真实DOM ,随后替换掉页面中之前的 真实DOM
b. 旧 虚拟DOM 中未找到与新 虚拟DOM 相同的 key
创建新的 真实DOM ,随后渲染到到页面 - 用 index 作为 key 可能会引发的问题
a. 若对数据进行逆序添加、逆序删除等破坏顺序操作,会产生没有必要的 真实DOM 更新 ==> 界面效果没问题,但效率低
b. 若结构中还包含输入类的 DOM :会产生错误 DOM 更新 ==> 界面有问题 - 开发中如何选择 key ?
a. 最好使用每条数据的唯一标识作为 key ,比如 id、手机号、身份证号、学号等唯一值
b. 如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表,使用 index 作为 key 是没有问题的
Vue核心 计算属性
- 定义:要用的属性不存在,需要通过已有属性计算得来
- 原理:底层借助了 Objcet.defineproperty() 方法提供的 getter 和 setter
- get 函数什么时候执行?
a. 初次读取时会执行一次
b. 当依赖的数据发生改变时会被再次调用 - 优势:与 methods 实现相比,内部有缓存机制(复用),效率更高,调试方便
- 备注
a. 计算属性最终会出现在 vm 上,直接读取使用即可
b. 如果计算属性要被修改,那必须写 set 函数去响应修改,且 set 中要引起计算时依赖的数据发生改变
c. 如果计算属性确定不考虑修改,可以使用计算属性的简写形式
watch 监视属性
深度监听
注意:
- Vue 自身可以监测对象内部值的改变,但 Vue 提供的 watch 默认不可以
使用 watch 时根据监视数据的具体结构,决定是否采用深度监视
watch: { //正常写法 // isHot: { // //handler什么时候调用?当ishot发生改变时,调用 // //immediate:true//初始化时让handler调用一下 // // deep:true 深度监视 // handler(newValue, oldValue) { // console.log('ishot被修改了') // } // } //简写 // isHot(newValue, oldValue) { // console.log('isHot被修改了', newValue, oldValue); // } }正常写法
vm.$watch('isHot', { //immediate:true//初始化时让handler调用一下 // // deep:true 深度监视 // handler(newValue, oldValue) { // console.log('ishot被修改了') // } })
计算属性 VS 监听属性
computed 和 watch 之间的区别
computed 能完成的功能, watch 都可以完成
watch 能完成的功能, computed 不一定能完成,例如 watch 可以进行异步操作
两个重要的小原则
所有被 Vue 管理的函数,最好写成普通函数,这样 this 的指向才是 vm 或 组件实例对象
所有不被 Vue 所管理的函数(定时器的回调函数、ajax 的回调函数等、Promise 的回调函数)
最好写成箭头函数,这样 this 的指向才是 vm 或 组件实例对象
小知识
多数被vue管理的函数用普通函数
多数不被vue管理的函数最好用箭头函数
v-if 多和template使用
模拟一个数据监测
let data = {
name: '小花',
address: '武汉'
}
// 创建一个监视的实例对象,用于检测data中属性的变化
const obs = new Observer(data)
console.log(obs)
//声明一个vm实例对象
let vm = {}
vm._data = data = obs
function Observer(obj) {
const keys = Object.keys(obj)
keys.forEach(k => {
Object.defineProperty(this, k, {
get() {
return obj[k]
},
set(val) {
console.log(`${k}被改了,我要去解析模板,生成虚拟DOM...我要开始忙了`);
obj[k] = val
}
})
})
}
Vue监测数据改变的原理
1.vue会监视data中所有层次的数据
2.如何检测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据.
(1).对象中后追加的属性,Vue默认不做响应式处理
(2).如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value)
vm.$set(target,propertyName/index,value)
3.如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1).调用元素怒哼对应的方法对数组进行更新
(2).重新解析模板,进行页面渲染.
4.在Vue修改数组中的某个元素一定要用如下方法:
(1)使用这些API:push() pop() shift() unshift() reverse() splice() sort()
(2)Vue.set()或 vm.$set()
特别注意:Vue.set() 和vm.$set() 不能给vm或者vm的根数据对象添加属性!!!
收集表单数据
收集表单数据:
若:<input type="text">,则v-model手机的时value值,用户输入的就是value的值
若:<input type="radio">,则v-model收集的是value,且要给标签配置value值
若:<input type="checkbox">
1.没有配置input的value属性,那么手机的就是checked(勾选or 未勾选,是布尔值)
2.配置input的value属性:
(1)v-model的初始值是非数组,那么手机的就是checked(勾选 or 不勾选,是布尔值)
(2)v-model的初始值是数组,那么手机的就是value组成的数组
备注:v-model的三个修饰符:
lazy:失去焦点在收集数据
number:输入字符串转为有效的数组
trim:输入首尾空格过滤
插值表达式
vue有一个最基本的功能: 数据渲染。 将数据(变量,或者利用ajax从后端获取到的数据)展示到页面上。
这里它不会直接操作dom,而是有自己的语法
在vue中{{ }}语法,叫做:插值表达式,大白话就是输出{{ }}中的表达式的值的语法。
把{{ }} 理解为一个占位符(一个坑), {{ msg }} 就是把msg显示在这个占位符中(把msg插到坑里面边去)
语法
{{ }} 可以:
● 写data数据字段名称
● 对data数据字段进行表达式运算
○ 拼接
○ 算术运算
○ 三元运算
○ ...
{{}}不能:
● js语句:声明变量,分支,循环
● 访问在vue实例中的data之外定义的自定义的变量
过滤器
过滤器:
定义:对要显示的数据进行特定格式化后再显示(适用一些简单逻辑操作)
语法:
1.注册过滤器:Vue.filter(name,callback)或new Vue(filters:{})
2.使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性='xxx| 过滤器名'
备注:
1.过滤器也可以接收额外参数、多个过滤器可以串联
2.并没有改变原来的数据,是产生新的对应的数据内置指令
之前学过的指令:
v-bind 单向绑定解析表达式,可简写为:
v-model 双向数据绑定
v-for 遍历数组 / 对象 / 字符串
v-on 绑定事件监听,可简写为 @
v-show 条件渲染 (动态控制节点是否展示)
v-if 条件渲染(动态控制节点是否存存在)
v-else-if 条件渲染(动态控制节点是否存存在)
v-else 条件渲染(动态控制节点是否存存在)v-text指令:
1.作用:向其所在的节点中渲染文本内容
2.与插值语法的区别:v-text会替换掉节点中的内容.{{xxx}}则不会v-html指令:
1.作用:向指定节点中渲染包含html结构的内容
2.与插值语法的区别:
(1).v-html会替换掉节点中所有的内容,{{xx}}则不会
(2).v-html可以识别html解构
3.严重注意:v-html有安全性问题!!!
(1).在网站上动态渲染任意HTML时非常危险的,容易导致xss攻击
(2).一定要在可信的内容上使用v-html,永不要在用户提交的内容v-once指令:
1.v-once所在节点在初次渲染后,就视为静态内容了
2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能.v-cloak指令(没有值):
1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题.
v-pre指令:
1.跳过其所在节点的编译过程
2.可以利用它跳过:没有使用指令语法、没有使用插值语法的节点、会加快编译.自定义指令总结:
一.定义语法:
(1)局部指令
new Vue({ new Vue({
directives:{指令名:配置对象} 或 directives{指令名:回调函数}
}) })
(2)全局指令:
Vue.directive(指令名,配置对象) 或 Vue.directive(指令名,回调函数)
二.配置对象中常用的3个回调:
(1).bind:指令与元素成功绑定时调用
(2).inserted:指令所在元素被插入页面时调用
(3).update:指令所在模板结构被重新解析时调用
三.备注:
1.指令定义时不加v-,但是用是要加v-;
2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名.自定义指令例子:备用图片处理
export const imgerror = {
// el 指令所在的元素
// binding 指令的相关信息对象, binding.value 指令的值
inserted(el, binding) {
// console.log(el, bindings)
el.onerror = function() {
// console.log('图片加载失败了'), 设置备用图片地址
el.src = binding.value
}
}
}引出声明周期
生命周期:
1.又名:生命周期回调函数、生命周期函数、生命周期钩子
2、是什么:Vue在关键时刻帮我们调一些特殊名称的函数
3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据实际需求编写的。
4。生命周期哈桑农户中的this指向是vm或组件实例对象。
常用生命周期钩子:
1.mounted:发送ajax请求、绑定自定义事件、订阅消息登[初始化操作]
2.beforeDestroy:清除定时器、解绑自定义事件、取消订阅消息等[收尾工作]
关于销毁Vue实例
1.销毁后借助Vue开发者工具看不到任何信息
2.销毁后自定义事件会失效,但原生DOM事件依然有效
3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会触发更新流程了.
Vue中使用组件的三大步骤:
一.定义组件(创建组件)
二.注册组件
三.使用组件(写组件标签)组件:局部功能的代码和资源的集合
一.如何定义一个组件?
使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options
几乎一致,但区别如下:
1.el不要写,为什么?-------最终所有的组件都要经过一个vm的管理,由于cm中的vm决定服务那个容器
2.data必须写成函数,为什么?------避免组件被复用时,数据存在引用关系.
备注:使用template可以配置组件结构
二.如何注册组件?
1.局部注册:靠new Vue的时候传入components选项
2.全局注册:靠Vue.component('组件名',组件)
三.编写组件标签
<school></school>关于组件名
1.一个单词组成
第一种写法(首字母小写):school
第二种写法(首字母大写):School2.多个单词组成
第一种写法(kebab-case 命名):my-school
第二种写法(CamelCase 命名):MySchool(需要 Vue 脚手架支持)
备注
组件名尽可能回避 HTML 中已有的元素名称,例如:h2、H2都不行
可以使用 name 配置项指定组件在开发者工具中呈现的名字3.关于组件标签
1.第一种写法: <school></school>
2.第二种写法: <school/> (需要 Vue 脚手架支持)
备注:不使用脚手架时, <school/> 会导致后续组件不能渲染
一个简写方式: const school = Vue.extend(options) 可简写为 const school = options ,因为父组件 components 引入的时候会自动创建关于 VueComponent
a. school 组件本质是一个名为 VueComponent 的构造函数,且不是程序员定义的,而是 Vue.extend() 生成的
b. 我们只需要写 <school/> 或
c. 每次调用 Vue.extend ,返回的都是一个全新的 VueComponent ,即不同组件是不同的对象
d. 关于 this 指向
ⅰ. 组件配置中 data 函数、 methods 中的函数、 watch 中的函数、 computed 中的函数 它们的 this 均是 VueComponent实例对象
ⅱ. new Vue(options) 配置中: data 函数、 methods 中的函数、 watch 中的函数、 computed 中的函数 它们的 this 均是 Vue实例对象
e. VueComponent 的实例对象,以后简称 vc (组件实例对象) Vue的实例对象 ,以后简称 vm
一个重要的内置关系
1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
2.为什么要有这个关系:让组件实例对象Vc可以访问到上Vue的属性、方法
Vue单文件组件
.vue是什么?
.vue文件是单文件组件
- 后缀名是
.vue - webpack会使用额外的loader来处理它
- 一个
.vue文件就是一个组件(页面) - 整个项目(页面)就是由多个组件构成的

基本组成
由三个部分组成:template + script + style
- template : 决定模块。类似于.html
- script: 代码逻辑。类似于.js
- style: 样式
<template>
<div class="box">
我是html模板
</div>
</template>
<script>
// 我是js逻辑
export default {
data() {
return {
// 定义变量,数据
}
}
}
</script>
<style>
/* 我是css样式 */
.box {
color:red
}
</style>组件进阶-动态组件
格式
<component :is="comName"></component>子组件
<template>
<div>
<h2>UserName</h2>
<p>用户名:<input /> </p>
<p>密码:<textarea /> </p>
</div>
</template>
<script>
export default {
}
</script>父组件
<template>
<div>
<button @click="comName = 'UserName'">账号密码填写</button>
<button @click="comName = 'UserInfo'">个人信息填写</button>
<p>下面显示注册组件:</p>
<div style="border: 1px solid red">
<!-- vue内置的组件component, 可以动态显示组件 -->
<component :is="comName"></component>
</div>
</div>
</template>
<script>
import UserName from "./UserName";
import UserInfo from "./UserInfo";
export default {
data() {
return {
comName: "UserName",
};
},
components: {
UserName,
UserInfo,
},
};
</script>注意
is只能是动态属性=》:is="组件注册后的标签名字符串或data变量"
不能直接拿注册标签名赋值使用
Vue内置的组件component,可以动态显示组件.
动态绑定is,他的值就是组件的名字(compoinents中的定义)来控制把哪个组件装进来组件进阶-keep-alive组件
组件切换会导致组件被频繁销毁和重新创建, 大多数情况下是有自己的意义的,但也可能会导致不必要的性能损耗
keep-alive
使用Vue内置的keep-alive组件, 可以让包裹的组件保存在内存中不被销毁
格式
演示2: 使用keep-alive内置的vue组件, 让动态组件缓存而不是销毁
补充生命周期:
● activated - 激活
● deactivated - 失去激活状态
<keep-alive>
<!-- vue内置的组件component, 可以动态显示组件 -->
<component :is="comName"></component>
</keep-alive>组件进阶-keep-alive组件-指定缓存
语法
- include="组件名1,组件名2..."
:include="['组件名1', '组件名2']"
<keep-alive include="name1,name2"> <!-- vue内置的组件component, 可以动态显示组件 --> <component :is="comName"></component> </keep-alive>注意:
匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)Vue CLI 初始化脚手架
说明
- Vue脚手架 是 Vue 官方提供的标准化开发工具(开发平台)
- 最新的版本是 4.x
- 文档 Vue CLI https://cli.vuejs.org/zh/
具体步骤
- 如果下载缓慢请配置 npm 淘宝镜像 npm config set registry http://registry.npm.taobao.org
- 全局安装 @vue/cli npm install -g @vue/cli
- 切换到创建项目的目录,使用命令创建项目 vue create xxx
- 选择使用 vue 的版本
- 启动项目 npm run serve
- 打包项目 npm run build
暂停项目 Ctrl+C
Vue脚手架 隐藏了所有 webpack 相关的配置,若想查看具体的 webpack 配置,请执行 vue inspect > output.js. 脚手架文件结构
文件目录 ├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ├── src │ ├── assets: 存放静态资源 │ │ └── logo.png │ │── component: 存放组件 │ │ └── HelloWorld.vue │ │── App.vue: 汇总所有组件 │ └── main.js: 入口文件 ├── .gitignore: git版本管制忽略的配置 ├── babel.config.js: babel的配置文件 ├── package.json: 应用包配置文件 ├── README.md: 应用描述文件 └── package-lock.json: 包版本控制文件
关于不同版本的函数
- vue.js 与 vue.runtime.xxx.js 的区别
a. vue.js 是完整版的 Vue ,包含:核心功能+模板解析器
b. vue.runtime.xxx.js 是运行版的 Vue ,只包含核心功能,没有模板解析器
esm 就是 ES6 module - 因为 vue.runtime.xxx.js 没有模板解析器,所以不能使用 template 配置项,需要使用 render 函数接收到的 createElement 函数去指定具体内容
vue.config.js 配置文件
vue inspect > output.js 可以查看到Vue脚手架的默认配置
使用 vue.config.js 可以对脚手架进行个性化定制,和 package.json 同级目录,
详见 配置参考 | Vue CLI https://cli.vuejs.org/zh/config/#vue-config-js
module.exports = {
pages: {
index: {
entry: 'src/index/main.js' // 入口
}
},
lineOnSave: false // 关闭语法检查
}
Vue CLI ref props mixin plugin scoped
1.ref属性
ref 被用来给元素或子组件注册引用信息(id的替代者)
应用在 html 标签上获取的是真实 DOM元素 ,应用在组件标签上获取的是组件实例对象 vc
使用方式
a. 打标识: <h1 ref="xxx"></h1> 或 <School ref="xxx"></School>
b. 获取: this.$refs.xxx
<template>
<div>
<h1 v-text="msg" ref="title"></h1>
<button ref="btn" @click="showDOM">点我输出上方的DOM元素</button>
<School ref="sch"/>
</div>
</template>
<script>
import School from './components/School'
export default {
name:'App',
components:{ School },
data() {
return {
msg:'欢迎学习Vue!'
}
},
methods: {
showDOM(){
console.log(this.$refs.title) // 真实DOM元素
console.log(this.$refs.btn) // 真实DOM元素
console.log(this.$refs.sch) // School组件的实例对象(vc)
}
},
}
</script>2. props 配置项
props 让组件接收外部传过来的数据
传递数据
接收数据
第一种方式(只接收) props:['name', 'age']
第二种方式(限制类型) props:{name:String, age:Number}
第三种方式(限制类型、限制必要性、指定默认值)
props: {
name: {
type: String, // 类型
required: true,// 必要性
default: 'cess'// 默认值
}
}
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}备注:props是只读的, Vue 底层会监测你对 props 的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制 props 的内容到 data 中,然后去修改 data 中的数据
3.mixin 混入
- 功能:可以把多个组件共用的配置提取成一个混入对象
使用方式
a. 定义混入const mixin = { data() {....}, methods: {....} .... }b. 使用混入
ⅰ. 全局混入 Vue.mixin(xxx)
ⅱ. 局部混入 mixins:['xxx']
备注组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”,在发生冲突时以组件优先
var mixin = { data: function () { return { message: 'hello', foo: 'abc' } } } new Vue({ mixins: [mixin], data () { return { message: 'goodbye', bar: 'def' } }, created () { console.log(this.$data) // => { message: "goodbye", foo: "abc", bar: "def" } } })- 同名生命周期钩子将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用
var mixin = {
created () {
console.log('混入对象的钩子被调用')
}
}
new Vue({
mixins: [mixin],
created () {
console.log('组件钩子被调用')
}
})
// => "混入对象的钩子被调用"
// => "组件钩子被调用"4.plugin 插件
- 功能:用于增强 Vue
- 本质:包含 install 方法的一个对象, install 的第一个参数是 Vue ,第二个以后的参数是插件使用者传递的数据
- 定义插件(见下 src/plugin.js)
使用插件: Vue.use()
export default { install(Vue,x,y,z){ console.log(x,y,z) //全局过滤器 Vue.filter('mySlice', function(value){return value.slice(0,4)}) //定义全局指令 Vue.directive('fbind',{ //指令与元素成功绑定时(一上来) bind(element,binding){element.value = binding.value}, //指令所在元素被插入页面时 inserted(element,binding){element.focus()}, //指令所在的模板被重新解析时 update(element,binding){element.value = binding.value} }) //定义混入 Vue.mixin({ data() {return {x:100,y:200}}, }) //给Vue原型上添加一个方法(vm和vc就都能用了) Vue.prototype.hello = ()=>{alert('你好啊')} }
5.scoped 样式
- 作用:让样式在局部生效,防止冲突
写法:
<style scoped>
Vue 中的 webpack 并没有安装最新版,导致有些插件也不能默认安装最新版,如 npm i less-loader@7,而不是最新版<template> <div class="demo"> <h2 class="title">学校名称:{{ name }}</h2> <h2>学校地址:{{ address }}</h2> </div> </template> <script> export default { name:'School', data() { return { name:'湖北', address:'襄阳', } } } </script> <style scoped> .demo{ background-color: skyblue; } </style>
Vue CLI Todo-List案例
组件化编码流程
- 拆分静态组件:组件要按照功能点拆分,命名不要与 html 元素冲突
- 实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用
一个组件在用:放在组件自身即可
一些组件在用:放在他们共同的父组件上(状态提升) - 实现交互:从绑定事件开始
props 适用于
a. 父组件 ==> 子组件 通信
b. 子组件 ==> 父组件 通信(要求父组件先给子组件一个函数)
使用 v-model 时要切记: v-model 绑定的值不能是 props 传过来的值,因为 props 是不可以修改的
props 传过来的若是对象类型的值,修改对象中的属性时 Vue 不会报错,但不推荐这样做
Vue CLI 本地存储 自定义事件
WebStorage(js 本地存储)
存储内容大小一般支持 5MB 左右(不同浏览器可能还不一样)
浏览器端通过 Window.sessionStorage 和 Window.localStorage 属性来实现本地存储机制
相关API
xxxStorage.setItem('key', 'value') 该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,
则更新其对应的值
xxxStorage.getItem('key') 该方法接受一个键名作为参数,返回键名对应的值
xxxStorage.removeItem('key') 该方法接受一个键名作为参数,并把该键名从存储中删除
xxxStorage.clear() 该方法会清空存储中的所有数据
备注
SessionStorage 存储的内容会随着浏览器窗口关闭而消失
LocalStorage 存储的内容,需要手动清除才会消失
xxxStorage.getItem(xxx) 如果 xxx 对应的 value 获取不到,那么 getItem() 的返回值是 null
JSON.parse(null) 的结果依然是 null组件的自定义事件
- 一种组件间通信的方式,适用于:子组件 ===> 父组件
- 使用场景:子组件想给父组件传数据,那么就要在父组件中给子组件绑定自定义事件(事件的回调在A中)
绑定自定义事件
a. 第一种方式,在父组件中<Demo @事件名="方法"/> 或 <Demo v-on:事件名="方法"/>
b. 第二种方式,在父组件中this.$refs.demo.$on('事件名',方法)<Demo ref="demo"/> ...... mounted(){ this.$refs.demo.$on('baiye',this.test) }c. 若想让自定义事件只能触发一次,可以使用 once 修饰符,或 $once 方法
- 触发自定义事件 this.$emit('事件名',数据)
- 解绑自定义事件 this.$off('事件名')
- 组件上也可以绑定原生 DOM 事件,需要使用 native 修饰符 @click.native="show"
上面绑定自定义事件,即使绑定的是原生事件也会被认为是自定义的,需要加 native ,加了后就将此事件给组件的根元素 - 注意:通过 this.$refs.xxx.$on('事件名',回调函数) 绑定自定义事件时,回调函数要么配置在 methods 中,要么用箭头函数,否则 this 指向会出问题
Vue CLI $nextTick 过渡与动画
1. $nextTick
这是一个生命周期钩子
this.$nextTick(回调函数) 在下一次 DOM 更新结束后执行其指定的回调
什么时候用:当改变数据后,要基于更新后的新 DOM 进行某些操作时,要在 nextTick 所指定的回调函数中执行
2. 过渡与动画
Vue 封装的过度与动画:在插入、更新或移除 DOM 元素时,在合适的时候给元素添加样式类名
写法
1. 准备好样式
元素进入的样式
ⅰ. v-enter 进入的起点
ⅱ. v-enter-active 进入过程中
ⅲ. v-enter-to 进入的终点
元素离开的样式
ⅰ. v-leave 离开的起点
ⅱ. v-leave-active 离开过程中
ⅲ. v-leave-to 离开的终点
- 使用
包裹要过度的元素,并配置 name 属性,此时需要将上面样式名的 v 换为 name 要让页面一开始就显示动画,需要添加 appear
<transition name="hello" appear> <h1 v-show="isShow">你好啊!</h1> </transition> <style> .hello-enter-active{ animation: hello 0.5s linear; } .hello-leave-active{ animation: hello 0.5s linear reverse; } @keyframes hello { from{ transform: translateX(-100%); } to{ transform: translateX(0px); } } </style>4. 备注:若有多个元素需要过度,则需要使用
,且每个元素都要指定 key 值 <transition-group name="hello" appear> <h1 v-show="!isShow" key="1">你好啊!</h1> <h1 v-show="isShow" key="2">尚硅谷!</h1> </transition-group>5. 第三方动画库 Animate.css
<transition-group appear name="animate__animated animate__bounce" enter-active-class="animate__swing" leave-active-class="animate__backOutUp"> <h1 v-show="!isShow" key="1">你好啊!</h1> <h1 v-show="isShow" key="2">尚硅谷!</h1> </transition-group>
Vue slot 插槽
slot 插槽<slot> 插槽:让父组件可以向子组件指定位置插入 html 结构,也是一种组件间通信的方式,
适用于 父组件 ===> 子组件
- 分类:默认插槽、具名插槽、作用域插槽
使用方式
a. 默认插槽父组件中: <Category> <div>html结构1</div> </Category> 子组件中:Category <template> <div> <!-- 定义插槽 --> <slot>插槽默认内容...</slot> </div> </templateb. 具名插槽
父组件指明放入子组件的哪个插槽slot="footer",如果是template可以写成v-slot:footer父组件中: <Category> <template slot="center"> <div>html结构1</div> </template> <template v-slot:footer> <div>html结构2</div> </template> </Category> 子组件中: <template> <div> <!-- 定义插槽 --> <slot name="center">插槽默认内容...</slot> <slot name="footer">插槽默认内容...</slot> </div> </template>c. 作用域插槽
scope用于父组件往子组件插槽放的 html 结构接收子组件的数据
理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定
将不带参数的 v-slot 假定为对应的默认 slot
可以使用v-slot="slotProps"替代v-slot:default="slotProps"
有多个 slot 的时候,不能将 v-slot 添加到标签上
<nav-head v-slot="slotProps">
{{ slotProps.data.key }}
</nav-head>个人理解:
如果在子组件定义了一个默认插槽,父组件想传入到这个插槽的结构只有一个html标签的话
可以省略template标签!
如果默认插槽要返回参数给父组件(作用域插槽)就要用template标签来接收
还有一种情况,如果在父组件中想传到默认插槽位置的结构不止一个html标签,也要带上template标签
可以使用 v-slot="slotProps"` 替代 `v-slot:default="slotProps"
v-slot:defalut 就是在父组件匹配子组件中的默认插槽注意:关于样式,既可以写在父组件中,解析后放入子组件插槽;也可以放在子组件中,传给子组件再解析
Vuex
1.Vuex是什么
概念:专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 Vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信
2.什么时候使用 Vuex
- 多个组件依赖于同一状态
- 来自不同组件的行为需要变更同一状态
3.. Vuex 工作原理图![2022-05-09T13:28:10.png 2022-05-09T13:28:10.png]()
4.. 搭建 Vuex 环境 - 下载安装 vuex npm i vuex
创建 src/store/index.js 该文件用于创建 Vuex 中最为核心的 store
import Vue from 'vue' import Vuex from 'vuex' // 引入Vuex Vue.use(Vuex) // 应用Vuex插件 const actions = {} // 准备actions——用于响应组件中的动作 const mutations = {} // 准备mutations——用于操作数据(state) const state = {} // 准备state——用于存储数据 // 创建并暴露store export default new Vuex.Store({ actions, mutations, state, })3. 在 src/main.js 中创建 vm 时传入 store 配置项
import Vue from 'vue' import App from './App.vue' import store from './store' // 引入store Vue.config.productionTip = false new Vue({ el: '#app', render: h => h(App), store, // 配置项添加store beforeCreate() { Vue.prototype.$bus = this } })4.使用 Vuex 编写
Vuex的基本使用:- 初始化数据 state ,配置 actions 、 mutations ,操作文件 store.js
- 组件中读取 vuex 中的数据 $store.state.数据
组件中修改 vuex 中的数据 $store.dispatch('action中的方法名',数据)
或 $store.commit('mutations中的方法名',数据)
若没有网络请求或其他业务逻辑,组件中也可越过 actions ,即不写 dispatch ,直接编写 commit四个map方法的使用
*1.mapState方法:用于帮助映射
state中的数据为计算属性computed: { // 借助mapState生成计算属性:sum、school、subject(对象写法一) ...mapState({sum:'sum',school:'school',subject:'subject'}), // 借助mapState生成计算属性:sum、school、subject(数组写法二) ...mapState(['sum','school','subject']), },2.mapGetters方法:用于帮助映射
getters中的数据为计算属性computed: { //借助mapGetters生成计算属性:bigSum(对象写法一) ...mapGetters({bigSum:'bigSum'}), //借助mapGetters生成计算属性:bigSum(数组写法二) ...mapGetters(['bigSum']) },3.mapActions方法:用于帮助生成与
actions对话的方法,即包含`$store.dispatch(xxx)的函数methods:{ //靠mapActions生成:incrementOdd、incrementWait(对象形式) ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'}) //靠mapActions生成:incrementOdd、incrementWait(数组形式) ...mapActions(['jiaOdd','jiaWait']) }4.mapMutations方法:用于帮助生成与
mutations对话的方法,即包含$store.commit(xxx)的函数methods:{ //靠mapActions生成:increment、decrement(对象形式) ...mapMutations({increment:'JIA',decrement:'JIAN'}), //靠mapMutations生成:JIA、JIAN(对象形式) ...mapMutations(['JIA','JIAN']), }
注意:mapActions与mapMutations使用时,若传递参数需要:在模板中绑定事件时传递好参数,否
则参数是事件对象
模块化+命名空间
1.目的:让代码更好维护,让多种数据分类更加明确
2.修改store.js
为了解决不同模块命名冲突的问题,将不同模块的namespaced:true,之后在不同页面中引入getter`actions`mutations时,需要加上所属的模块名
const countAbout = {
namespaced: true, // 开启命名空间
state: {x:1},
mutations: { ... },
actions: { ... },
getters: {
bigSum(state){ return state.sum * 10 }
}
}
const personAbout = {
namespaced: true, // 开启命名空间
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
countAbout,
personAbout
}
})3.开启命名空间后,组件中读取state数据
// 方式一:自己直接读取
this.$store.state.personAbout.list
// 方式二:借助mapState读取:
...mapState('countAbout',['sum','school','subject']),4.开启命名空间后,组件中读取getters数据
//方式一:自己直接读取
this.$store.getters['personAbout/firstPersonName']
//方式二:借助mapGetters读取:
...mapGetters('countAbout',['bigSum'])5.开启命名空间后,组件调用dispatch
//方式一:自己直接dispatch
this.$store.dispatch('personAbout/addPersonWang',person)
//方式二:借助mapActions:
...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})6.开启命名空间后,组件中调用commit
//方式一:自己直接commit
this.$store.commit('personAbout/ADD_PERSON',person)
//方式二:借助mapMutations:
...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
v-model是语法糖
语法糖:对一更加复杂的操作的封装,讨好程序员的.
// 1. v-model 在表单元素上使用
<input v-model="xxx" />
// 2. v-model 在自己定义的组件上使用
<MyCom v-model="xxx" />
上面的写法是快捷方式,它等价于如下复杂的写法:
<MyCom :value="xxx" @input="新值=>xxx=新值" />
// v-model做两件事:
// 1. 向子组件传来一个名为value的属性
// 2. 在子组件监听input事件,这个事件的回调中修改value所绑定的值问:为啥要在自己的组件上用v-model?
答:v-model写法比较简单,一个指令实现两个功能:子传父(input事件),父传子(value属性)。
问:可不可以不用?
答:可以。
vue2响应式的缺点
响应式:数据改变-->视图跟着变
对象新增的属性没有响应式
数组的部分操作没有响应式
main.js 批量注册指令
1.按需导入时的重命名, 使用 as 进行重命名
import * as results from './xxx.js'
2.批量注册用 Object.keys (推荐) 遍历对象, 优先用Object.keys, 先转数组
import * as directives from '@/directives'
// 批量注册全局的自定义指令
Object.keys(directives).forEach(key => {
Vue.directive(key, directives[key])
})针对上面的引入语法 import * as 变量 得到的是一个对象{ 变量1:对象1,变量2: 对象2 ... },
可以采用 Object.keys 得到一个对象键的数组, 进行遍历处理
main.js 批量注册组件
利用 Vue.use 统一全局注册组件
- Vue.use 可以接收一个对象, Vue.use(obj)
- 对象中需要提供一个 install 函数
- install 函数可以拿到参数 Vue, 且将来会在 Vue.use 时, 自动调用该 install 函数
提供统一注册的入口文件src/componets/index.js
// 该文件负责所有的公共组件的全局注册
// vue插件机制: Vue.use
// Vue.use(params)方法中可以params传递函数或对象作为参数
// params 一般是一个对象 对象中有一个方法 名称叫install
// 1.当Vue.user(obj) install 这个方法会自动地执行
// 2.install方法中有形参 这个形参时Vue
import PageTools from './PageTools'
export default {
install(Vue) {
Vue.component('PageTools', PageTools)
}
}在入口处进行注册 src/main.js Vue.use 注册使用自己的插件模块
import Components from './components'
Vue.use(Components) 
最新回复