Vue

vue3知识点

2021-10-15  本文已影响0人  郭_小青

Vue.js

核心是一个允许采用简洁的模板语法来声明式地将数据渲染进DOM的系统
组件本质上是一个具有预定义选项的实例
const app = vue.createApp({ ... }) // 在应用中创建“全局”组件

// 创建 Vue 应用实例
const app = Vue.createApp(...)

// 定义名为 todo-item 的新组件
app.component('todo-item', {
  template: `<li>This is a todo</li>`
})

// 挂载 Vue 应用
app.mount(...)

Demo

const ComponentsApp = {
  data() {
    return {
      groceryList: [
        { id: 0, text: 'Vegetables' },
        { id: 1, text: 'Cheese' },
        { id: 2, text: 'Whatever else humans are supposed to eat' }
      ]
    }
  }
}
// 允许链式写法
// Vue.createApp({})
//  .component('SearchInput', SearchInputComponent)
//  .directive('focus', FocusDirective)
//  .use(LocalePlugin)

const app = Vue.createApp(ComponentsApp)
app.component('todo-item', {
  props: ['todo'],
  template: `<li>{{ todo.text }}</li>`
})
app.mount('#components-app')
<div id="todo-list-app">
  <ol>
     <!--
      现在我们为每个 todo-item 提供 todo 对象
      todo 对象是变量,即其内容可以是动态的。
      我们也需要为每个组件提供一个“key”,稍后再
      作详细解释。
    -->
    <todo-item
      v-for="item in groceryList"
      v-bind:todo="item"
      v-bind:key="item.id"
    ></todo-item>
  </ol>
</div>
一、根组件
  1. 传递给createApp的选项用于配置根组件。当我们挂载应用时,该组件被用作渲染的起点
  2. *** 根组件与其他组件没有什么不同,配置选项是一样的,所对应的组件实例 行为也是一样的
  3. *** mount 返回的是根组件实例,不是应用本身

Vue 应用挂载到 <div id="app"></div>

const RootComponent = { 
  /* 选项 */ 
}
const app = Vue.createApp(RootComponent)
const vm = app.mount('#app') 
二、生命周期
  1. 生命周期函数、选项property(元素属性)或回调上不可使用箭头函数。生命周期钩子this上下文指向调用它的当前活动实例。
  2. 箭头函数并没有this,this作为变量一直向上级词法作用域查找。直至找到为止,经常导致Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。
  vue.createApp({
    data() {
      return { count: 1 }
    },
    created() {
      console.log('count is' + this.count) // => count is 1
    }
  })
image.png
三、模板语法

在底层的实现上,Vue将模板编译成虚拟DOM渲染函数。结合响应性系统,Vue能够智能地计算出最少需要重新渲染多少组件,并把DOM操作次数减到最少。
*** v-html不能复合局部模板,因为Vue不是基于字符串的模板引擎,反之,对于用户界面(UI),组件更适合作为可重用和可组合的基本单位
*** 动态渲染任意的HTML是非常危险的,因为很容易导致XSS攻击

1. 文本插值使用双大括号{{ 变量 }}
2. 动态渲染HTML使用v-html
  const RenderHtmlApp = {
    data() {
      return {
        rawHtml: '<span style="color: red">这几个文字是红色</span>'
      }
    }
  }
  Vue.createApp(RenderHtmlApp).mount('#example')
<div id="example">
  <p> v-html解析<span v-html="rawHtml"></span> </p>
</div>
3. 插值双大括号{{ 单个表达式 }}可以使用js表达式
{{ n + 1 }}
{{ ok ? 'Yes' : 'No' }}
{{ arrayData.split(',') }}
...
{{ var a = 1 }} // 不会生效, 这是语句,不是表达式
{{ if( ok ) { return message } }} // 流控制也不会生效
4. v- 指令职责是:当表达式的值改变时,将其产生的连带影响,响应式作用于DOM
5. 参数
<a v-on:click="doSomthing"> ... </a>
6. 动态参数

*** 动态参数预期是求出一个字符串,异常情况下为null。这个null会被显性地用于移除绑定

// 若attrname的值为click
<a v-on:[attrname]="doSomthing">...</a> 
等价于
<a v-on:click="doSomthing">...</a>

*** 在 DOM 中使用模板时 (直接在一个 HTML 文件里撰写模板),还需要避免使用大写字符来命名键名,因为浏览器会把 attribute 名全部强制转为小写:

<!--
在 DOM 中使用模板时这段代码会被转换为 `v-bind:[someattr]`。
除非在实例中有一个名为“someattr”的 property,否则代码不会工作。
-->
<a v-bind:[someAttr]="value"> ... </a>
7. 缩写

v-on

// 完整语法
<a v-on:click="doSomthing">...</a>
// 缩写
<a @click="doSomthing">...</a>
// 动态参数缩写
<a @[attrname]="doSomthing">...</a>

v-bind

// 完整语法
<a v-bind:href="url">...</a>
// 缩写
<a :href="url">...</a>
// 动态参数缩写
<a :[key]="url">...</a>
四、Data Property

vue自动为methods绑定this,以便它始终指向组件实例。这将确保方法再用作事件监听或回调时保持正确的this。定义methods时应避免使用箭头函数

1. vue没有内置的防抖、节流,可以引用lodash

为了使组件实例彼此独立,可以在生命周期钩子created里添加防抖函数

app.component( 'save-button', {
    created() {
      // 使用lodash 防抖函数
      this.debouncedClick = _.debounce(this.click, 500)
    },
    unmounted() {
      // 移除组件时,取消定时器
      this.debouncedClick.cancle()
    },
    methods: {
      click() {
        // ... 响应事件...
      }
    },
    template: `
      <button @click='debouncedClick'> Save </button>
    `
  })
五、计算属性、侦听器
1.computed 计算属性

computed:{ ... }计算属性是基于它们的响应依赖关系缓存的。

以下:如果data的值不发生改变,即使多次访问computFun计算属性会立即返回之前的计算结果,而不必再次执行函数。如果不希望缓存,可用methods来代替

computed: {
  computFun() {
    return this.data == 1 ? '是' :'否'
  }
}

以下计算属性将不再更新,因为Date.now()不是响应式依赖

  computed: {
    now() {
      return Date.now()
    }
  }
2.watch 侦听器

当需要在数据变化时执行异步 或 开销较大的操作时,watch方式最有用

六、条件渲染

v-ifv-else-ifv-elsev-show

1.v-if、v-else-if、v-else

v-if和v-for不推荐同时使用,如果一起使用了v-if的优先级更高

<template>元素当做不可见的包裹元素,在上面使用v-if。最终的渲染结果不包括<template>元素

<template v-if="ok">
 <p>渲染后template标签不存在</p>
</template>
 // ok为true, 渲染结果为
<p>渲染后template标签不存在</p>
2.v-show

v-show的元素始终会被渲染并保留在DOM中,v-show只是简单地切换元素的CSS property display
**** v-show不支持<template>元素,也不支持v-else

3.v-if VS v-show
七、列表渲染

用v-for把一个数组对应为一组元素

1.数组
  • item为迭代数组元素别名。index为索引。key作为Vue识别节点的一个通用机制,key需使用字符串或数值类型的值
  • v-for可以在template元素中使用

当Vue正在更新使用v-for渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染

v-for与v-if同时使用时建议使用以下写法:

<template v-for="(item, index) in items" :key="item.id">
  <li v-if="!item.isShow">{{item.name}}</li>
  <li>{{item.name}}</li>
</template>
2.对象
  • value为value。name为key。index为索引
  • 会按照object.keys()结果遍历对象,但是不能保证它在不同JavaScript引擎下的结果一致
<li v-for="(value, name, index) in myObject">
  {{ index }}. {{ name }}: {{ value }}
</li>
3.数组更新

变更方法:变更调用了这些方法的原始数组
替换数组:即非变更方法,不会变更原始数组,而总是返回一个新数组

由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。当你直接修改了对象属性的值,会发现只有数据改了,页面内容没有更新。Vue将被侦听数组的变更方法进行了包裹,所以它们也将会触发视图更新。

八、事件处理
1. @click监听点击事件
<button @click="btnFun('click me', $event)">点击事件</button>
...
methods: {
  btnFun(msg, event) {
    // doSomthing
  }
}
2. @click多事件处理器
<button @click="one($event), two($event)">处理多事件按钮</button>
...
methods: {
  one(event) {
    // 第一个事件处理逻辑
  },
  two(event) {
    // 第二个事件处理逻辑
  }
}

3. 事件修饰符

.stop、.prevent、.capture、.self、.once、.passive

使用修饰符时,顺序很重要;相应代码会以同样的顺序产生

<!-- 阻止单击事件继续传播 -->
<a @click.stop="doThis"></a>

<!-- 提交事件不再重载页面 -->
<form @submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a @click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form @submit.prevent></form>

<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div @click.capture="doThis">...</div>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div @click.self="doThat">...</div>
<!-- 点击事件将只会触发一次 -->
<a @click.once="doThis"></a>
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发   -->
<!-- 而不会等待 `onScroll` 完成                   -->
<!-- 这其中包含 `event.preventDefault()` 的情况   -->
<div @scroll.passive="onScroll">...</div>
4. 其它修饰符

直接将 KeyboardEvent.key 暴露的任意有效按键名转换为 kebab-case 来作为修饰符

<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input @keyup.enter="submit" />
<input @keyup.page-down="onPageDown" />
<!-- Alt + Enter -->
<input @keyup.alt.enter="clear" />

<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick">A</button>

<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick">A</button>
九、表单输入绑定
1. 值绑定
<!-- 当选中时,`picked` 为字符串 "a" -->
<input type="radio" v-model="picked" value="a" />

<!-- `toggle` 为 true 或 false -->
<input type="checkbox" v-model="toggle" />

<!-- 当选中第一个选项时,`selected` 为字符串 "abc" -->
<select v-model="selected">
  <option value="abc">ABC</option>
</select>
<!-- 当选中时vm.pick === vm.a-->
<input type="radio" v-model="pick" v-bind:value="a" />
2. 修饰符
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg" />
<input v-model.number="age" type="number" />
<input v-model.trim="msg" />
十、组件基础
<button @click="$emit('enlargeText', 0.1)">
  Enlarge text
</button>
...
methods: {
  onEnlargeText(enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}
1. 动态组件

以下currentTabComponent可以包括:已注册的名字 或 一个组件的选项对象

<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component :is="currentTabComponent"></component>
// blog-post-row为 自定义组件
<table>
  <tr is="vue:blog-post-row"></tr> 
</table>
2. 属性名称 大小写

HTML attribute 名不区分大小写,因此浏览器将所有大写字符解释为小写。这意味着当你在 DOM 模板中使用时,驼峰 prop 名称和 event 处理器参数需要使用它们的 kebab-cased (横线字符分隔) 等效

app.component('blog-post', {
  props: ['postTitle'],
  template: `
    <h3>{{ postTitle }}</h3>
  `
})
...
<blog-post post-title="hello!"></blog-post>
十一、组件注册
1.全局注册: 在注册以后可以用在任何新创建的组件实例模板中

app.component的第一个参数是组件名

const app = Vue.createApp({ ... })
app.component('my-component-name', {
  ...
})

...
<my-component-name></my-component-name>
2.局部注册: 在components选项中定义组件以后才可使用

局部注册的组件在其子组件中不可使用

在 ComponentB 中可用ComponentA。举例:

const ComponentA = {
  /* ... */
}

const ComponentB = {
  components: {
    'component-a': ComponentA
  }
  // ...
}

import ComponentA from './ComponentA'
import ComponentC from './ComponentC'

export default {
  components: {
    ComponentA,
    ComponentC
  }
  // ...
}
十二、props:父组件向子组件传值

props单向下绑定的数据流向。数据只能从父组件流向子组件,在子组件中不可修改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() {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator(value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].includes(value)
      }
    },
    // 具有默认值的函数
    propG: {
      type: Function,
      // 与对象或数组默认值不同,这不是一个工厂函数 —— 这是一个用作默认值的函数
      default() {
        return 'Default function'
      }
    }
  }
})

用于验证author prop的值是否通过new Person创建的。举例:

function Person(firstName, lastName) {
  this.firstName = firstName
  this.lastName = lastName
}

...可以使用

app.component('blog-post', {
  props: {
    author: Person
  }
})
const app = Vue.createApp({})

app.component('blog-post', {
  // camelCase in JavaScript
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})

...

<!-- kebab-case in HTML -->
<blog-post post-title="hello!"></blog-post>
上一篇下一篇

猜你喜欢

热点阅读