vue学习
箭头函数
function() => {
}
js位置
JavaScript代码可以直接嵌在网页的任何地方,不过通常我们都把JavaScript代码放到中;
可以在同一个页面中引入多个.js文件,还可以在页面中多次编写,浏览器按照顺序依次执行。
由于浏览器的安全限制,以file://开头的地址无法执行如联网等JavaScript代码,最终,你还是需要架设一个Web服务器,然后以http://开头的地址来正常执行所有JavaScript代码。
js分号
JavaScript并不强制要求在每个语句的结尾加;
数字判断
唯一能判断NaN的方法是通过isNaN()
函数
要特别注意相等运算符==。JavaScript在设计时,有两种比较运算符:
第一种是==比较,它会自动转换数据类型再比较,很多时候,会得到非常诡异的结果;
第二种是===比较,它不会自动转换数据类型,如果数据类型不一致,返回false,如果一致,再比较。
这不是JavaScript的设计缺陷。浮点数在运算过程中会产生误差,因为计算机无法精确表示无限循环小数。要比较两个浮点数是否相等,只能计算它们之差的绝对值,看是否小于某个阈值:
Math.abs(1 / 3 - (1 - 2 / 3)) < 0.0000001; // true
动态语言与静态语言
变量本身类型不固定的语言称之为动态语言,与之对应的是静态语言。
动态参数
...
当eventName
的值为"focus"
时,v-on:[eventName]
将等价于v-on:focus
。
v-bind
v-bind:属性,单向绑定?
v-on
事件监听,v-on:click=""
,简写@click=""
2.6.0新增动态参数,可以根据条件响应不同的事件
需要注意的是,动态表达式中更不要有引号和空格,因为对于html的attribute名来说这些符号无效,同时浏览器会将attribute名转为小写,所以也不要有大写字符
防抖与节流
有些函数如mousemove触发的函数会在短时间内连续调用多次,如果要使其在一段事件内只执行一次函数,就需要防抖与节流.
防抖:每隔一段事件才触发一次
节流:连续触发后,每隔一段时间才处理一次
//防抖
function debounce(fn, wait) {
let timeout = null
return function() {
if(timeout !== null) clearTimeout(timeout)
timeout = setTimeout(fn, wait);
}
}
function handle() {
console.log(Math.random())
}
window.addEventListener('scroll', debounce(handle, 1000))
计算属性
一般来说,模板要求简单的、声明性的,如{{label}}
,但是有时会过于复杂如:
{{ author.books.length > 0 ? 'Yes' : 'No' }}
虽然代码可以工作,但是过于复杂,推荐使用计算属性来声明
{{ publishedBooksMessage }}
computed: {
// 计算属性的 getter
publishedBooksMessage() {
// `this` points to the vm instance
return this.author.books.length > 0 ? 'Yes' : 'No'
}
}
计算属性与方法比较:计算属性在响应式依赖改变时才会重新求值,而函数在每次调用时都会重新执行
{{ countBooks1() }}
{{ countBools2 }}
methods:{
countBooks1() {
return books.length
}
},
computed:{
countBooks2() {
return books.length
}
}
计算属性可以设置setter和getter
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]
}
}
}
侦听器watch
可以在响应式数据变化的时候执行函数,相比于计算属性,watch可以执行异步操作如访问api,但是开销比计算属性大
watch: {
// whenever question changes, this function will run
question(newQuestion, oldQuestion) {
if (newQuestion.indexOf('?') > -1) {
this.getAnswer()
}
}
}
truthiness真值
在js中,除了false
、0
、""
、null
、undefined
和NaN
之外都为真值。
if (true)
if ({})
if ([])
if (42)
if ("foo")
if (new Date())
if (-42)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)
:class
:class="{ active: isActive }"
class为isActive
值,当isActive
为nul
时,没有class。
此外,:class
可以与class
属性共存,:class
内也可以有多个值,或者使用数组来提供class
data() {
return {
activeClass: 'active',
errorClass: 'text-danger'
}
}
:style语法
:style
的对象语法十分直观——看着非常像CSS,但其实是一个JavaScript对象。CSS property名可以用驼峰式(camelCase)或短横线分隔(kebab-case,记得用引号括起来)来命名
条件渲染
条件渲染有两种:v-if
和v-show
。v-if
只有在条件为真时才渲染条件快,可以和v-else-if
和v-else
配合使用。v-show
总是会被渲染,真假值变化体现为css的变化
v-for
可以来对应数组,也可以对应对象。
对应数组时,两个参数依次分别表示值和索引;
对应对象时,三个参数依次分别表示值、键和索引。
-
{{ parentMessage }} - {{ index }} - {{ item.message }}
{{ index }}. {{ name }}: {{ value }}
当v-for对应的数据中的数据项改变了顺序,vue不会移动DOM元素来匹配数据,而是使用“就地更新”的策略,如果想要对应的DOM元素改变位置,需要添加:key
属性
数组更新检测
数组变更
以下函数可以触发视图更新
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
数组替换
以下函数可以保留原来数组,且返回新的数组
filter()
concat()
slice()
显示过滤、排序数组
可以在v-for
中使用计算属性或者方法
在组件上使用v-for
因为组件自己独立的作用域,所以在定义组件的时候要使用props
来传递参数。
const app = Vue.createApp({
data() {
return {
newTodoText: '',
todos: [
{
id: 1,
title: 'Do the dishes'
},
{
id: 2,
title: 'Take out the trash'
},
{
id: 3,
title: 'Mow the lawn'
}
],
nextTodoId: 4
}
},
methods: {
addNewTodo() {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText
})
this.newTodoText = ''
}
}
})
app.component('todo-item', {
template: `
{{ title }}
`,
props: ['title']
})
app.mount('#todo-list-example')
事件处理
若在事件处理中要访问原始的DOM事件,可以用特殊变量$event传入方法
warn(message, event) {
if (event) {
event.preventDefault()
}
}
一个事件可以有多个方法处理,方法间使用逗号分隔
event.preventDefault() 与 event.stopPropagation()
event.preventDefault()
阻止事件的默认动作发送,比如点击勾选框不能切换勾选状态、在input框输入非规定内的字符就无法输入等等。
event.stopPropagation()
仍会执行默认动作,但是执行完后事件不再被分派到其他节点。
js冒泡与捕获
首先我们需要形成监听器的思想。在不使用任何框架的情况下,我们在js中通过addEventListener
方法给Dom添加事件监听。这个方法直译就是添加事件监听器。我们对Dom的操作作为事件会从最外面的祖先Dom逐步传递到目标Dom(捕获过程),然后再从目标的Dom原路传出去(冒泡过程)。通常我们只监听冒泡过程。在vue中,当我们添加了事件修饰符capture
后,才会变成捕获监听器。
所以vue中的.stop
修饰符的停止传播就容易理解了,一般来说在冒泡监听时,是有内层的子DOM开始到外层的祖先DOM,设置了.stop
后,在本DOM处理事件后,事件便不再冒泡。
而.self
可以理解为跳过冒泡事件和捕获事件,只有直接作用在该元素上的事件才可以执行。
事件修饰符
.stop
执行事件后停止传播.prevent
不执行默认动作,相当于执行event.preventDefault()
.capture
由冒泡监听改为捕获监听.self
跳过冒泡事件和捕获事件,只有直接作用在该元素上的事件才可以执行.once
只执行一次.passive
不会执行event.preventDefault()
按键修饰符
使用@监听键盘事件
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.right
修饰键
修饰键与常规按键不同,只有在按住修饰键的情况下释放其它按键,才能触发事件。而单单释放修饰键也不会触发事件。
Do something
键盘修饰键
.ctrl
.alt
.shift
.meta
鼠标修饰键
.left
.right
.middle
.exact
修饰符
.exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。
v-model
对于单选按钮,复选框及选择框的选项,v-model 绑定的值通常是静态字符串 (对于复选框也可以是布尔值)v-model
有三种修饰符
.lazy
在“change”时而非“input”时更新.number
将用户的输入值转为数值类型,如果这个值无法被 parseFloat() 解析,则会返回原始的值.trim
自动过滤用户输入的首尾空白字符
组件基础
因为组件是可复用的组件实例,所以它们与new Vue
接收相同的选项,例如data
、computed
、watch
、methods
以及生命周期钩子等。通过component
可以进行全局注册。
// 定义一个名为 button-counter 的新全局组件
app.component('button-counter', {
data() {
return {
count: 0
}
},
template: `
`
})
prop
通过prop
定义属性并向子组件传递数据
const app = Vue.createApp({})
app.component('blog-post', {
props: ['title'],
template: `{{ title }}
`
})
app.mount('#blog-post-demo')
监听子组件事件
通过使用$emit
来传入外部的事件名称,也可以将内部参数传出。
app.component('blog-post', {
props: ['title'],
template: `
{{ title }}
`
})
实现组件的v-model双向绑定
为了在组件中可以使用v-model
,组件需要向外暴露出一个接受的prop
,并且向内规定该数据的getter
和setter
。getter
、setter
可以通过计算属性实现。
app.component('custom-input', {
props: ['modelValue'],
template: `
`,
computed: {
value: {
get() {
return this.modelValue
},
set(value) { this.$emit('update:modelValue', value)
}
}
}
})
简单插槽
组件中在需要插入的位置使用
标签,在使用组件时直接用组件名标签包裹。
Something bad happened.
app.component('alert-box', {
template: `
Error!
`
})
动态加载组件
使用属性:is
可以地将简单组件载入到该位置。
const tabs = [
{
name: 'Home',
component: {
template: `Home component`
}
},
{
name: 'Posts',
component: {
template: `Posts component`
}
},
{
name: 'Archive',
component: {
template: `Archive component`
}
}
]
const app = Vue.createApp({
data() {
return {
tabs,
currentTab: tabs[0]
}
},
computed: {
currentTabComponent() {
return 'tab-' + this.currentTab.toLowerCase()
}
}
})
app.component('tab-home', {
template: `Home component`
})
app.component('tab-posts', {
template: `Posts component`
})
app.component('tab-archive', {
template: `Archive component`
})
app.mount('#dynamic-component-demo')
特殊DOM解析注意事项
形如 建议使用kebab-case (短横线分隔命名) 局部注册需要引用 在传入值时,由两种方式: 静态赋值vue会视为一个字符串,而 特别地,当一个对象的所有属性都需要传入时,可以使用不带参数的 我们已经知道, 可以定义数据类型、指定默认值和自定义验证规则。 非Prop的Attribute,指的是不定义在 事件监听器的继承也同理,会默认继承到组件内部根元素。 需要注意的是,如果要使非根节点继承,需要在组件的选项中设置 命名推荐使用 在组件中,在 在组件中更可以自定义v-model修饰符。但是需要注意的是,修饰符的具体方法是写在属性的setter函数中,并且修饰符的名称为 在组件的模板中可以定义 在需要多个插槽的情况下,为了识别不同的插槽,需要给每一个插槽一个名字 A paragraph for the main content. And another one. Here's some contact info 若想让外部访问组件内部的数据(比如用在插入内容时需要组件内部数据),可以将组件模板中插槽的属性设置为数据。 {{slotProps.item}} 由于 只有在有参数的情况下才可以缩写,使用 如果在一个多层嵌套的组件链中,内层的组件要获得外层组件的数据,有两种方法: 第一种是前面讲过的设置 第二种是父组件提供数据,子组件注入数据的模式,我们可以使用 注入的数据默认是非响应式的,如果想要响应式的数据注入,需要分配一个组合式API 在一些场景比如切换标签页中,不停地切换标签页会不断地重新渲染组件。使用保活标签 不是很懂,目前也暂时用不到,等第二次阅读时再细究。 如果需要在js中访问组件,可以使用、
、
等等这些标签对于哪些子标签可以出现在其内部是由严格规定的(比如可以出现在 中)。而有些标签如
、
和 等只能出现在特定的元素内部。如果在这些特定标签内部使用自定义的组件,可能会导致出错。此时可以使用
v-is
属性来帮助解析组件。
深入组件
组件命名
局部注册
import ComponentA from './ComponentA.vue'
export default {
components: {
ComponentA
}
// ...
}
prop类型
prop
可以设置类型,在设置错误时会在控制台提示用户。props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // 或任何其他构造函数
}
动态传入Prop
v-bind
或缩写:
告诉vue这是一个js表达式。v-bind
。post: {
id: 1,
title: 'My Journey with Vue'
}
单向数据流
prop
中定义外部传入的数据。如果我们希望这些数据成为本地数据,可以供子组件使用,并且在数据更新时,子组件也会更新,与此同时反过来不行(会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解)的话,可以将定义在prop
中的属性定义为一个data property
或者计算属性。// 定义为data
props: ['initialCounter'],
data() {
return {
counter: this.initialCounter
}
}
// 定义为计算属性
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
prop数据验证
app.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function() {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function(value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
},
// 具有默认值的函数
propG: {
type: Function,
// 与对象或数组默认值不同,这不是一个工厂函数 —— 这是一个用作默认值的函数
default: function() {
return 'Default function'
}
}
}
})
非Prop的Attribute继承
prop
中的属性,如class
、id
、style
等等。在外部使用组件时并使用这些属性时,默认会继承给组件内部的根元素;如果根元素有多个或者想要继承到非根元素,可以使用v-bind="$attrs"
($attrs
包括组件props
和emits property
中未包含的所有属性 (例如class
、style
、v-on
监听器等)。)来选定一个DOM元素继承。
inheritAttrs: false
。app.component('date-picker', {
inheritAttrs: false,
template: `
自定义事件
kebab-case
(短横线连接)的事件名,因为v-on
事件监听器在DOM模板中会被自动转换为全小写。自定义事件可以和prop
属性一样进行验证。app.component('custom-form', {
emits: {
// 没有验证
click: null,
// 验证submit 事件
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
},
methods: {
submitForm() {
this.$emit('submit', { email, password })
}
}
})
v-model参数与多个v-model绑定
prop
中定义的属性,在外部可以用v-model:属性名
的方式来进行多个v-model
绑定。自定义v-model修饰符
arg + "Modifiers"
。const app = Vue.createApp({
data() {
return {
myText: ''
}
}
})
app.component('my-component', {
props: {
name: String,
nameModifiers: {
default: () => ({})
}
},
methods: {
emitValue(e) {
let value = e.target.value
if (this.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
this.$emit('update:name', value)
}
},
template: ``
})
app.mount('#app')
插槽
标签,可以替换为字符串、html代码或其他组件。当
标签中间有内容时,这部分内容会作为默认。具名插槽
name
,不带name
的插槽会有一个隐含的名字“default”。在外部使用组件的具名插槽的时候,使用的
v-slot
指示插槽名称。注意必须使用v-slot
时必须在标签中。
Here might be a page title
v-slot
的值是作为函数参数作用的,所以可以写成任何能够作为函数定义中的参数的JavaScript表达式。
v-slot
同样可以使用动态参数具名插槽的缩写
#
代替v-slot
。提供与注入
prop
,但是不方便的是这需要在每一层组件都设置prop
,开发上稍微有点麻烦;provide
和inject
对。父组件可以作为其所有子组件的依赖项提供程序,而不管组件层次结构有多深。这个特性有两个部分:父组件有一个provide
选项来提供数据,子组件有一个inject
选项来开始使用这个数据。computed
属性。// 父组件提供
app.component('todo-list', {
data() {
return {
todos: ['Feed a cat', 'Buy tickets']
}
},
provide() {
return {
todoLength1: this.todos.length,
todoLength2: Vue.computed(() => this.todos.length) //响应式
}
},
template: `
...
`
})
app.component('todo-list-statistics', {
inject: ['todoLength'],
created() {
console.log(`Injected property: ${this.todoLength1}`) // > 注入 property: John Doe
}
})
保活标签keep-alive
可以保持这些组件的状态,以避免反复重渲染导致的性能问题。异步组件
模板引用
ref
为组件或HTML元素指定引用ID。注意,由于$refs
只会在组件渲染完成之后生效,应该避免在模板或计算属性中访问$refs
。const app = Vue.createApp({})
app.component('base-input', {
template: `
`,
methods: {
focusInput() {
this.$refs.input.focus()
}
},
mounted() {
this.focusInput()
}
})
你可能感兴趣的:(每周总结 20210801 vue文档学习)