目录
1、Element Placement Restrictions
data-property
data是一个函数,这些实例 property 仅在实例首次创建时被添加。
// data函数返回一个对象,并用响应性系统包裹。以 $data 的形式存储在组件实例中
console.log(vm.$data.count) // => vm是实例,$data是包装过后的响应式的属性
console.log(vm.count) // => 为了方便,data对象的属性被“直接暴露”
method
1、Vue 自动为 methods
绑定 this
,以便于它始终指向组件实例。
2、避免使用箭头函数
3、普通调用
<button @click="increment">Up vote</button>
4、模板中访问:这种情况一般使用计算属性,但是如果计算属性不行的时候可以使用方法
<!-- 3、模板中访问 -->
<span :title="toTitleDate(date)">{{ formatDate(date) }}</span>
计算属性
1、模板中的判断都应该换成计算属性或者method
2、基于它们的响应依赖关系缓存的。这也同样意味着下面的计算属性将不再更新,因为 Date.now () 不是响应式依赖:
computed: {
now() {
return Date.now() // 没有响应式依赖,依赖没有变化,计算属性不更新。
// 可能是因为 Date.now 这个的结果是一个复杂对象?地址没有变化吗?
}
}
3、计算属性的set
computed: {
fullName: {
// getter
get() {
return this.firstName + ' ' + this.lastName
},
// setter
set(newValue) {
const names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
侦听器
Class 与 Style 绑定
1、普通
2、对象
3、数组
4、在组件中使用:带有数据绑定的也同样适用,会把父组件中的 truthy 的值传过去
<!-- 1个根元素的组件 -->
<div id="app">
<my-component class="baz boo"></my-component>
</div>
<!-- 子组件 -->
<p class="child1 child2 baz boo">Hi</p>
<!-- 多根元素的组件 -->
<div id="app">
<my-component class="baz"></my-component>
</div>
app.component('my-component', {
template: `
<p :class="$attrs.class">Hi!</p>
<span>This is a child component</span>
`
})
条件渲染
v-if
与 v-for
一起使用时,v-if
优先级大。这意味着 v-if
将没有权限访问 v-for
里的变量
<!-- ❗❗❗ 报错:"todo" is not defined on instance.可以把 v-for 移动到 <template> 标签中来修正 -->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>
列表渲染
1、v-for 可以遍历 对象
<ul id="v-for-object" class="demo">
<li v-for="(value, key, index) in myObject">
{{ value }}——{{key}}
</li>
</ul>
<!-- 'How to do lists in Vue'——title -->
<!-- 'Jane Doe'——author -->
<!-- '2016-04-10'——publishedAt -->
myObject: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
2、数组的方法合集 :改变原数组的方法 、不改变原数组的方法
事件处理
1、多事件处理器
<!-- 这两个 one() 和 two() 将执行按钮点击事件 -->
<button @click="one($event), two($event)">
Submit
</button>
2、事件修饰符:修饰符是有顺序的
.stop :阻止冒泡
.prevent:阻止默认行为
.capture:即是给元素添加一个监听器,当元素发生冒泡时,先触发带有该修饰符的元素。若有多个该修饰符,则由外而内触发。
.self:事件由本身触发时才调用函数
.once:只执行一次
.passive:不阻止默认行为。不能和.prevent修饰符一同使用,否则浏览器会报错。可能看到这里会疑惑,默认行为不是本来就不阻止的吗?这里就讲到浏览器机制:【浏览器只有等内核线程执行到事件监听器对应的JavaScript代码时,才能知道内部是否会调用preventDefault函数来阻止事件的默认行为,所以浏览器本身是没有办法对这种场景进行优化的。这种场景下,用户的手势事件无法快速产生,会导致页面无法快速执行滑动逻辑,从而让用户感觉到页面卡顿。】 通俗点说就是每次事件产生,浏览器都会去查询一下是否有preventDefault阻止该次事件的默认动作 ,加上 passive 就是提前告诉浏览器,我们没阻止。这一般用在移动端,滚动监听 / 触摸事件 ,因为滚动事件会每个像素触发一次事件,每次都使用内核线程查询prevent会使滑动卡顿,如果用了 .passive 就将内核线程查询跳过,直接不阻止。大大提升流畅性
<a @click.stop="doThis"></a>
<!-- 修饰符可以串联 -->
<a @click.stop.prevent="doThis"></a>
<!-- 只有修饰符,没有函数 -->
<form @submit.prevent></form>
3、按键修饰符
-
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.righ
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input @keyup.enter="submit" />
4、系统修饰键
.ctrl
.alt
.shift
.meta (
command键 或者 Windows键 )
5、exact
修饰符
精确的系统修饰符组合触发的事件
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>
6、鼠标按钮修饰符
.left .right .middle
表单输入绑定
基础用法
v-model:对于不同输入框使用不同事件绑定
1、text / textarea :value 属性和 input 事件
2、checkbox 、radio :checked 属性 和 change 事件
3、select:value 属性 和 change 事件
选择框
select:v-model 的值未匹配任何选项,select 会渲染成 ”未选中“的状态。但在 IOS会导致用户无法选择第一个选项,所以这个情况下,推荐使用一个值为空的禁用选项。
<select v-model="selected">
<option disabled value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
Vue.createApp({
data() {
return {
selected: ''
}
}
}).mount('#v-model-select')
值绑定
修饰符
.lazy:input 框默认方法是 input 方法,然后又如果写成 @input.lazy 的话,就只会在 Change 的时候改变
.number
.trim
组件基础
组件复用:
每使用一次组件,就有一个组件实例被创建
组件的组织
全局注册
const app = Vue.createApp({})
app.component('my-component-name', {
// ... 选项 ...
})
局部注册
// 在 componentB 组件中注册 ComponentA 和 ComponentC
import ComponentA from './ComponentA'
import ComponentC from './ComponentC'
export default {
components: {
ComponentA,
ComponentC
}
// ...
}
监听子组件事件
1、使用事件抛出一个值
注意函数名的大小写 enlargeText → @enlarge-text
<!-- 父组件 -->
<blog-post ... @enlarge-text="postFontSize += 0.1"></blog-post>
<!-- 子组件 -->
<button @click="$emit('enlargeText')">
Enlarge text
</button>
2、在组件上使用 v-model ⭐
1、方法一:@update:xxx
v-model 是一个语法糖,等于 @input + value ,用在组件上的效果如下
<custom-input v-model:visiable="value1"></custom-input>
<!-- 等价于 -->
<custom-input :visiable="value1" @update:visiable="value1 = $event"></custom-input>
<!-- 咱一般使用的 v-model 如下 -->
<input v-model="test">
子组件内做如下操作
prop:['visiable']
emits: ['update:visiable'],
// 函数里面发请求
emit('update:visiable',false)
2、方法2(使用计算属性)
app.component('custom-input', {
props: ['value'],
emits: ['update:value'],
template: `
<input v-model="myValue">
`,
computed: {
myValue: {
get(){
return this.value
},
set(val){
this.$emit('update:value',val)
},
}
}
})
通过插槽分发内容 ⭐
子组件
app.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})
父组件
<alert-box>
Something bad happened.
</alert-box>
动态组件
应该注意的是,下面讨论的限制仅适用于直接在 DOM 中编写模板的情况。它们不适用于以下来源的字符串模板:
- 字符串模板 (比如
template: '...'
)- 单文件组件
<script type="text/x-template"> // script 里面直接写 html 代码
例如切换 tab 栏的时候,组件不同,这时候就可以用到动态组件
<!-- 组件会在 `currentTabComponent` 改变时改变,is对应组件名 -->
<component :is="currentTabComponent" v-bind="componentProps"></component>
解析 DOM 模板时的注意事项
1、Element Placement Restrictions
ul 里面必须是 li ,如何在 ul 里面直接放自定义组件?
2、Case Insensitivity
深入组件
组件注册
Props
单向数据流⭐
1、父传子,且子不可以更改
Ⅰ:prop 普通类型传值复杂类型传递引用。所以如果是复杂对象,子改父将会影响到父组件
Ⅱ:prop 会在组件实例创建之前进行验证,所以 prop 里面无法使用 data、computed 里的数据
2、如果子想更改父,有两种方式:
Ⅰ:data 使用 prop 的值,子组件内使用data 的值
props: ['initialCounter'],
data() {
return {
counter: this.initialCounter
}
}
Ⅱ:computed 里使用 Prop 的值,子组件使用 prop。(prop 需要进行转换时 )
props: ['size'],
computed: {
normalizedSize() {
return this.size.trim().toLowerCase()
}
}
Prop验证
1、`null` 和 `undefined` 会通过任何类型验证
2、多个类型用数组来表示。prop 的 type 属性的值是数组,如 [Number, String]
3、复杂类型的 default 用函数来返回
4、Prop 还可以传递函数
5、
app.component('my-component', {
props: {
propA: Number, // 基础的类型检查
propB: [String, Number], // 多个可能的类型 ⭐
propC: { type: String, required: true },// 必填的字符串
propD: { type: Number, default: 100 }, // 带有默认值的数字
propE: { type: Object, default() { return { message: 'hello' } } }, // ⭐ 带有默认值的对象。 对象/数组 默认值必须从一个工厂函数获取
propF: {
validator(value) {
return ['success', 'warning', 'danger'].includes(value) // 值必须是下列中的一个
}
}, // 自定义验证函数
propG: {
type: Function,
default() {
return 'Default function' // ⭐函数类型 Prop, 这是用作默认值的函数。详细见 YQ 项目个人档案详情页
}
} // 具有默认值的函数
}
})