Vue基础

介绍

一套用于构建用户界面的渐进式框架,被设计为可以自底向上逐层应用,核心库只关心视图层

问题:什么叫渐进式框架?

progressive framework, vue对自己框架和其他框架对比后,生成的一个特定名词

问题:vue的核心是什么?

用模板的方式进行一系列的编译,有自己的核心库会编译模板,然后会渲染 DOM

Vue将数据于 DOM进行关联,并建立响应式关联,数据改变视图更新

优点:

应用范围广,生态环境友好,社区完善,易上手,代码轻量,发展迅速

注意:兼容性问题,IE8及以下不支持 vue

区别

  • Angular是一个综合性框架,也是一个开发平台,用于创建高效,复杂,精致的单页面应用

    • 关注项目应用
    • 不关注视图渲染和状态管理
    • 适合开发大型应用
    • 高度集成方法
    • 自上而下的延展
  • React是构建用户界面的 JavaScript

    • 关注视图层
    • 数据渲染视图
    • 管理视图和状态关系
    • 没有状态中央管理(需借助 Redux)
    • 不提供路由(react-router)
    • 自下而上的延展
  • Vue是视图层的核心库

    • 关注用户界面
    • 关注视图层
    • 关注数据渲染视图
    • 可以选择集成 Vuex
    • 可以选择集成 Vue-router
    • 微型库概念(Micro libs)
    • 自下而上的延展
    • 库和库的集合形成框架

安装

方法一:

vite + cdn 方式

  1. //1.初始化项目
  2. npm init -y
  3. //2.安装打包依赖
  4. npm i -D vite@2.3.8
  5. //3.修改 package.json 里script的dev为vite
  6. //4.新建 index.html
  7. //5.写入入口标签
  8. <div id="app"></div>
  9. //6.引入 vue cdn 地址
  10. <script src="https://unpkg.com/vue@3.1.2/dist/vue.global.js"></script>
  11. //7.引入入口文件
  12. //type="module" es6原生写法要求
  13. <script type="module" src="./src/main.js"></script>
  14. //8.启动项目
  15. npm run dev
  16. //9.启动成功
  17. //10.入口文件编写
  18. const { createApp } = Vue;
  19. const App = {
  20. data() {
  21. return {
  22. text: 'Hello Vue!'
  23. }
  24. },
  25. template: `<h1>{{text}}</h1>`
  26. }
  27. createApp(App).mount('#app');
  28. //11.页面显示 Hello Vue!

补充:cdn 加速网站


方法二:

结合webpack打包工具搭建项目

vue2.x项目搭建:

注:因为 Vue提供了编写单文件组件的配套工具,如果想要使用单文件组件,2.0 得需安装vue-template-compilervue-loader依赖,3.0 则需安装vue/compiler-sfc依赖

  1. //1.项目初始化
  2. npm init -y
  3. //2.webpack依赖安装
  4. npm i -D webpack@4.44.2
  5. npm i -D webpack-cli@3.3.12
  6. npm i -D webpack-dev-server@3.11.2
  7. //3.更改 package.json 脚本命令scripts为dev: webpack-dev-server
  8. //4.新建 index.html
  9. //5.写入入口标签
  10. <div id="app"></div>
  11. //6.引入vue2.x的cdn
  12. <script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
  13. //7.安装依赖
  14. npm i -D vue-loader@15.9.7
  15. npm i -D vue-template-compiler@2.6.14
  16. npm i -D html-webpack-plugin@4.5.0
  17. //8.配置webpack.config.js, 详细代码往下看
  18. const { resolve } = require('path');
  19. const HtmlWebpackPlugin = require('html-webpack-plugin');
  20. const VueLoaderPlugin = require('vue-loader/lib/plugin');
  21. //node环境下commonjs规范:
  22. module.exports = {
  23. mode: 'development',
  24. entry: './src/main.js',
  25. output: {
  26. path: resolve(__dirname, 'dist'),
  27. filename: 'main.js'
  28. },
  29. //配置外部文件
  30. externals: {
  31. 'vue': 'Vue'
  32. },
  33. devtool: 'source-map',
  34. module: {
  35. rules: [{
  36. test: /\.vue$/,
  37. loader: 'vue-loader'
  38. }]
  39. },
  40. plugins: [
  41. new VueLoaderPlugin(),
  42. new HtmlWebpackPlugin({
  43. template: resolve(__dirname, 'public/index.html')
  44. })
  45. ]
  46. }
  47. //9.启动项目
  48. npm run dev
  49. //10.编写入口文件
  50. new Vue({
  51. render: h => h(App)
  52. }).$mount('#app');
  53. //11.编写app组件
  54. <template>
  55. <div>{{ title }}</div>
  56. </template>
  57. <script>
  58. export default {
  59. name: "App",
  60. data() {
  61. return {
  62. title: "Hello Vue",
  63. };
  64. },
  65. };
  66. </script>
  67. //12.浏览器成功显示渲染后的页面

vue3.x项目搭建:基于2.x的文件做以下修改

  1. //1.修改入口文件为3.x写法
  2. Vue.createApp(App).mount('#app');
  3. //2.引入vue3.x的cdn
  4. <script src="https://unpkg.com/vue@3.1.2/dist/vue.global.js"></script>
  5. //3.安装3.x依赖
  6. npm i -D @vue/compiler-sfc
  7. npm i -D vue-loader@16.3.0 //vue-loader@next
  8. //4.更改配置文件 webpack-config.js 的 vue-loader 引入
  9. const { VueLoaderPlugin } = require('vue-loader');
  10. //5.启动项目
  11. npm run dev
  12. //6.浏览器成功渲染

进一步配置:

  1. npm i -D sass-loader@10.1.1
  2. npm i -D sass@1.35.2
  3. npm i -D autoprefixer@10.3.1
  4. npm i -D css-loader@4.3.0
  5. npm i -D postcss-loader@4.3.0
  6. npm i -D postcss@8.3.6
  7. npm i -D vue-style-loader@4.1.3
  8. npm i -D @vue/devtools@5.3.4

webpack.config.js配置代码:

  1. const {
  2. resolve
  3. } = require('path');
  4. const HtmlWebpackPlugin = require('html-webpack-plugin');
  5. // const VueLoaderPlugin = require('vue-loader/lib/plugin');
  6. const {
  7. VueLoaderPlugin
  8. } = require('vue-loader');
  9. const autoprefixer = require('autoprefixer');
  10. //node环境下commonjs规范:
  11. module.exports = {
  12. mode: 'development',
  13. entry: './src/main.js',
  14. output: {
  15. path: resolve(__dirname, 'dist'),
  16. filename: 'main.js'
  17. },
  18. //配置外部文件
  19. externals: {
  20. 'vue': 'Vue'
  21. },
  22. devtool: 'source-map',
  23. module: {
  24. rules: [{
  25. test: /\.vue$/,
  26. loader: 'vue-loader'
  27. }, {
  28. test: /\.scss$/,
  29. use: [
  30. 'vue-style-loader',
  31. 'css-loader',
  32. {
  33. loader: 'postcss-loader',
  34. options: {
  35. postcssOptions: {
  36. plugins: [
  37. autoprefixer({
  38. overrideBrowserslist: [
  39. "> 1%",
  40. "last 2 versions"
  41. ]
  42. })
  43. ]
  44. }
  45. }
  46. },
  47. 'sass-loader'
  48. ]
  49. }]
  50. },
  51. plugins: [
  52. new VueLoaderPlugin(),
  53. new HtmlWebpackPlugin({
  54. template: resolve(__dirname, 'public/index.html')
  55. })
  56. ]
  57. }

package.json的配置代码:

  1. {
  2. "name": "vue-webpack-demo",
  3. "version": "1.0.0",
  4. "description": "",
  5. "main": "index.js",
  6. "scripts": {
  7. "dev": "webpack-dev-server",
  8. "build":"webpack"
  9. },
  10. "keywords": [],
  11. "author": "",
  12. "license": "ISC",
  13. "devDependencies": {
  14. "@vue/compiler-sfc": "^3.1.5",
  15. "html-webpack-plugin": "^4.5.0",
  16. "vue-loader": "^16.4.1",
  17. "vue-template-compiler": "^2.6.14",
  18. "webpack": "^4.44.2",
  19. "webpack-cli": "^3.3.12",
  20. "webpack-dev-server": "^3.11.2"
  21. }
  22. }

模板语法

template里面的一些 HTML字符串内部除开 HTML本身特性以外 Vue的特性,如文本,表达式,属性,指令等

Vue模板都是基于 HTML的,模板中直接写 HTML都是能够被 HTML解析器解析的

Vue提供一套模板编译系统

基本是开发者写的template,然后分析它将 HTML字符串变成AST树,把表达式/自定义属性/指令等转化为新的原生的 HTML,把 JS写法的 HTML模板遍历出来后形成虚拟 DOM树节点,最后根据虚拟 DOM树变成真实 DOM树渲染到页面上

问题:如何虚拟 DOM对比真实 DOM数据?

将真实 DOM数据转为对象结构存储,再进行对比,有差别的情况下形成新的补丁再一定的算法基础下替换

插值

数据绑定最常见的形式就是使用Mustache语法 (双大括号) 的文本插值:

  1. //title为字符串
  2. <h1 id="title"></h1>
  3. //title为变量
  4. <h1 v-bind:id="title"></h1>
  5. var url = "https://www.baidu.com";
  6. //html -> 插入JS的表达式 -> v-bind:href="url";

标签内部插入表达式

  1. {{}}

属性上插入表达式

  1. v-bind:xx=""

关于mustache.js

它是一个零依赖的模板系统,mustache中是不支持在 HTML属性中插值的,Vue中因为用底层的模板编译系统,支持内置的属性

  1. npm i -S mustache
  1. import Mustache from 'mustache';
  2. var data = {
  3. title: 'This is my TITLE for MUSTACHE'
  4. }
  5. var html = Mustache.render(
  6. `<h1>{{title}}</h1>`,
  7. data
  8. );
  9. document.getElementById('app').innerHTML = html;

关于属性:

  • attribute:HTML 的拓展 title/src/href
  • property:在对象内部存储数据,通常用来描述数据结构 prop

关于表达式:

作用:数学运算/字符串拼接/判断/JS API/不能绑定多个表达式/绑定语句

  1. //数学运算
  2. <h1 :title="a + b">{{a+b}}</h1>
  3. //字符串拼接
  4. <h2>{{'a + b =' + (a + b)}}</h2>
  5. //判断表达式
  6. <h3>{{a + b > 5 ? '大于5' : '小于等于5'}}</h3>
  7. <h3>{{title || subTitle}}</h3>
  8. //使用JS API
  9. <h4>{{title.replace('main', '')}}</h4>
  10. <h4>{{subTitle.split('').reverse().join('-')}}</h4>
  11. //绑定语句 报错
  12. {{ var a = 1; }}

指令

指令 (Directives) 是带有 v- 前缀的特殊 attribute,它一般结合视图模板使用,响应式的作用于dom

问题:为什么叫指令?

模板应该按照怎样的逻辑进行渲染或绑定行为

内置指令有:

v-if/v-else/v-else-if/v-for/v-show/v-html/v-once

自定义指令:

开发者也可以给 Vue拓展指令,v-自定义名称

v-model:数据双向绑定 用v-model="数据来源"实现,也是一个语法糖,是@input="方法":input="数据"的语法糖

适用元素:input/textarea/select/checkbox/radio

注意:使用v-model会忽略这些属性value/checked/selected

v-bind绑定属性,目的是引号内部看做变量,vue会对它进行解析

注意:插值表达式里的变量必须是实例里面定义的属性

  1. //绑定数据变量
  2. v-bind:title="被绑定变量,这里绑定内容是插值表达式里的内容"
  3. <p v-bind:title="content">{{content}}</p>
  4. //动态的属性名参数不能出现空格和引号,HTML的合法属性名不能出现空格引号
  5. <h1 v-bind:[attr]="tag">{{title}}</h1>
  6. //null作为属性是无效的,可以利用null解除属性绑定
  7. <h1 v-bind:[null]="title">{{title}}</h1>
  8. //简写
  9. <p :title="变量">{{content}}</p>
  10. <p title="字符串">{{content}}</p>

v-on事件绑定方法,类似于onclick/addEventListener绑定事件处理函数

  1. //简写@click="likeThisArticle"
  2. <span>Like: {{like}}</span>
  3. <button v-on:click="likeThisArticle"></button>

v-if为真就显示/为假不显示

  1. <button v-if="isLogin" v-on:click="likeThisArticle"></button>
  2. <button v-else disabled>Please login first!</button>

v-model视图双向绑定,vue完成了数据双向绑定的机制,好处是业务关注点全部可以放到业务逻辑层,而视图层交给了v-model帮助渲染和更新

  1. //写一个评论
  2. <div class="form">
  3. //oninput事件会将其value交给myComment数据变量
  4. //v-model这个特点会更改视图
  5. <input type="text" placeholder="请填写评论" v-model="myComment" />
  6. </div>

v-for遍历,列表渲染

  1. //v-for必须搭配key表示唯一性 key 属性必须是唯一的值
  2. <li v-for="item of commentList" :key="item.id"></li>
  3. //遍历数组
  4. <ul>
  5. <li v-for="(item, index) of list" :key="item.id">
  6. <span>{{item.id}}</span>
  7. <span>{{item.name}}</span>
  8. </li>
  9. <ul>
  10. //遍历计算属性
  11. computed: {
  12. computedList(){
  13. return this.list.map(item => {
  14. item.pass = item.score >= 60;
  15. return item;
  16. })
  17. }
  18. }
  19. <ul>
  20. <li v-for="item of computedList" :key="item.id">
  21. <span>Order {{index}}</span>
  22. </li>
  23. <ul>
  24. //遍历method里的方法属性
  25. var myArr = [[1,2,3],[4,5,6],[7,8,9,0]];
  26. method: {
  27. even(numbers){
  28. return numbers.filter(number => number % 2 === 0);
  29. }
  30. }
  31. <ul v-for="numbers of myArr">
  32. <li v-for="number of even(numbers)">
  33. {{number}}
  34. </li>
  35. <ul>
  36. //值范围
  37. <span v-for="star in 5" :key="star">※</span>
  38. //组件与v-for
  39. //item是不会自动传入组件的 :item="item"
  40. //1.避免v-for与组件功能与数据耦合
  41. //2.保证组件有合理的配置性
  42. //3.达到最后的复用效果
  43. <ul>
  44. <list-item
  45. v-for="item of list"
  46. :key="item.id"
  47. :item="item"
  48. >
  49. </list-item>
  50. </ul>

v-once:一次插值,永不更新,不建议

v-html:安全原因,插值不会解析 HTML,因为插值是 JS表达式,没有对 DOM的操作,rawHTML原始 HTML,不要试图用v-html做子模版,vue本身有一个底层的模板编译系统,而不是直接使用字符串来渲染的

  1. //子模版放到子组件中,让模板的重用和组合更强大
  2. //不要把用户提供的内容作为`v-html`的插值,这种插值容易导致 XSS 攻击
  3. const App = {
  4. data(){
  5. return {
  6. title: 'This is my Title'
  7. }
  8. },
  9. template: `
  10. {{title}}
  11. `
  12. }
  13. Vue.createApp(App).mount('#app');

v-if/v-else-if/v-else:分支判断是否渲染视图

v-show:隐藏节点,是否显示

关于条件渲染v-if/v-show的区别:

  • v-if是对 DOM的移除和添加,在移除的时候用注释节点占位,对内部的子组件与事件监听都会销毁与重建
  • v-if只有条件是 truthy的时候,才会被渲染(惰性渲染)
  • v-show总会会被渲染,用 display来控制其显示与隐藏
  • v-if在切换的时候会提高开销,如果条件为假值,初始化渲染是不会进行的
  • v-show在切换的时候开销较低,但是初始化渲染时无论显示与否都要被渲染

v-if/v-show的使用选择:

  • 如果切换频繁就用v-show
  • 如果切换不频繁,(加载时不需要的视图),可以用v-if

特殊attribute

ref引用

ref引用,reference被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。

如果在普通的 DOM元素上使用,引用指向的就是 DOM元素;如果用在子组件上,引用就指向组件实例

vue里是不需要操作 dom的,也不需要去获取 dom,有些场景需要去对 dom节点进行获取,也可能对 dom节点相关的信息,万不得已的情况下对节点进行操作

  1. //拿到组件的实例
  2. //也可以访问实例底下的属性和方法
  3. <my-list ref="myRef"></my-list>

组件的实例的实际应用:

兄弟组件相互调用方法或者获取属性

注意:

  • $refs本身并不是响应式的,所以不要在模板中使用
  • 不要在计算属性中访问,因为不具备响应式
  • 不要尝试更改 ref, 它提供给获取节点或实例引用,并不是改变的

问题:为什么要获取组件实例?

可以通过调用组件相关的方法获取相应的属性,兄弟组件的情况下,需要获取自己兄弟上面的方法或者是属性的时候,可以用 ref把组件的实例拿出来,然后在实例上去使用属性和方法

问题:为什么尽量不使用 ref?

因为 vue是数据绑定机制,经常使用 ref可能导致 vue的解决方案的匮乏, dom的增删改查是 ViewModel实现的而不是开发者去操作的

  1. //通过$refs(vue内部方法的引用集合)可以访问dom里面的属性
  2. <input ref="myRef"></input>
  3. console.log(this.$refs.myRef);

注:$refs 早在生命周期 beforeCreate时候已经存在了,只有组件装载完毕后(mounted)才存在 myRef

问题:为什么只有组件装载完毕后才存在 myRef?

如果没有挂载,节点就不会存在,那么就无法拿到指定节点的引用,说明在有些开发场景遇到 refnull/undefined 时要考虑组件是否加载完毕后才去获取 dom引用


案例:移动端滚动页面加载更多

技术:ref(html dom)

实现上下滚动页面渲染加载更多或者暂无数据

原理:

通关 ref标签属性拿到绑定在dom节点里面的clientHeight/scrollHeight/scrollTop数据进行计算是否触底,从而每次触底时新增 5 条数据渲染到页面

源码地址:

https://gitee.com/kevinleeeee/ref-dom-demo

应用实例

问题:应用实例是什么?

通过createApp创建 APP返回一个应用实例

  1. //Application 应用 返回一个vue实例对象
  2. const app = Vue.createApp({});
  3. console.log(app);

应用实例里面的 component属性主要是用来注册全局组件

  1. app.component('MyTitle', {
  2. data(){
  3. return {
  4. title: 'I Love You!'
  5. }
  6. },
  7. template: `<h1>{{title}}</h1>`
  8. });
  9. app.mount('#app');

<template></template>标签里使用组件

  1. <div>
  2. <!-- 写法一 -->
  3. <MyTitle />
  4. <!-- 写法二 -->
  5. <my-title />
  6. </div>

在实例上暴露了很多方法,如 :

  • component注册组件
  • directive注册全局自定义指令
  • filter注册过滤器
  • mixin全局注册混入器
  • provide注入全局跨组件层级的属性
  • use使用插件

实例里的大多数方法都会返回 createApp创建出来的应用实例,目的是允许链式调用操作

生命周期

组件是有初始化过程的,在过程中,Vue提供了很多每个阶段运行的函数,函数会在对应的初始化阶段自动运行

实例的生命周期过程:

  • 创建实例并挂载:app = Vue.createApp(options); app.mount(el)
  • 执行完后初始化事件和生命周期,实例对象身上有默认的一些生命周期函数和默认事件
  • beforeCreate阶段
  • 初始化,数据注入,整理好跟视图相关的响应式开发相关特性(初始化 data/method)
  • created阶段
  • 判断是否有模板:编译模板,把 data对象里面的数据和 Vue语法写的模板编译成 HTML

    • 有:编译模板至渲染函数
    • 没:编译 elinnerHTML至模板
  • 挂载之前执行beforeMount阶段
  • 创建app.$el(真实的根节点)并添加至 el
  • mounted阶段
  • 已挂载状态监听数据是否存在变化

    • 有变化,虚拟节点对应补丁重新渲染更新
  • beforeUpdate阶段
  • 更新完之后到updated阶段
  • 调用app.unmount()方法后会销毁组件
  • 销毁组件经历两个阶段:

    • beforeUnmount阶段
    • unmounted阶段

1.基础 - 图1

data属性

逻辑区域的对象里的 data,它的核心有:

  • data 必须是一个函数
  • vue 在创建实例的过程中调用 data 函数,返回数据对象
  • 通过响应式包装后存储在实例的$data
  • 并且实例可以直接越过$data可访问属性

问题:为什么要用data?

每次组件实例时先执行data()返回一个函数来保证数据的引用是唯一的

  1. //data()方法执行返回一个对象
  2. const app = Vue.createApp({
  3. data(){
  4. return {
  5. title: 'This is my Title'
  6. }
  7. },
  8. template: `
  9. <h1>{{title}}</h1>
  10. `
  11. });
  12. cosnt vm = app.mount('#app');
  13. console.log(vm);
  14. //$, _, __ 都是vue提供的内置API
  15. //开发者尽量避免用这些前缀命名自己的属性和方法
  16. /**
  17. * console.log(vm):
  18. * Proxy{...}
  19. * title: 'This is my Title'
  20. * $: ...
  21. * $el: ...
  22. * $emit: ...
  23. * $data: Proxy
  24. * title: 'This is my Title'
  25. */
  26. console.log(vm.$data.title);
  27. //This is my Title
  28. //越过$data访问title
  29. console.log(vm.title);
  30. //This is my Title
  31. vm.$data.title = 'This is your Title';
  32. console.log(vm.title);
  33. //This is your Title
  34. vm.title = 'This is my Title';
  35. console.log(vm.$data.title);
  36. //This is my Title
  37. //说明vm.title 和 vm.$data.title都是同一个数据
  38. //$data是响应式数据对象
  39. vm.autor = 'kevin';
  40. console.log(vm.author); //kevin
  41. console.log(vm.$data.author); //找不到
  42. //这个写法会被vue警告,且需要在data里定义author变量
  43. vm.$data.author = 'kevin';
  44. console.log(vm.author); //kevin
  45. console.log(vm.$data.author); //kevin

问题:data 为什么必须是一个函数?

如果 data是一个对象的话,那么很难防止同一引用重复使用的问题,而每次实例 Vue执行函数都会返回一个新的对象可以解决同一对象引用的问题

  1. //此写法会报错,vue时刻监听data是否为一个函数
  2. //Uncaught TypeError: dataOptions.call is not a function
  3. const App = {
  4. data: {
  5. a: 1
  6. },
  7. template: `
  8. <h1>{{a}}</h1>
  9. `
  10. }
  11. Vue.createApp(App).mount('#app');

methods属性

逻辑区域的对象里的 逻辑方法都写在 method的对象里,向组件实例添加方法

Vue创建实例时,会自动为 methods绑定当前实例 this,保证在事件监听时,回调始终指向当前组件实例,方法要避免使用箭头函数,箭头函数不能更改 this指向,箭头函数会阻止 Vue正确绑定组件实例 this

  1. methods: {
  2. likeThisArticle(){
  3. this.like ++;
  4. }
  5. }
  1. //注意:函数名 + () 不是执行符号,是传入实参的容器
  2. @click="changeTitle('xxx')"
  3. //拆分写法
  4. onclick = "() => { changeTitle('xxx')}"
  5. //可以在视图模板里 方法函数的执行 响应式的执行
  6. //注意:模板直接调用的方法尽量避免副作用操作 如更改数据,异步操作
  7. //
  8. <h1>{{ yourTitle() }}</h1>

注:methods里的定义的方法是存放在 vm实例对象里,而不是 methods里,因为可以让实例直接调用改方法

computed属性

计算属性的核心:

  • 解决模板中复杂的逻辑运算及复用的问题
  • 计算属性旨在内部逻辑依赖的数据发生变化的时候才会被再次调用
  • 计算属性会缓存(缓存在实例里)其依赖的上一次计算出的数据结果
  • 多次复用一个相同值数据,计算属性只调用一次(只要 data数据没有发生更改就不会调用)
  1. //这个情景反映一个问题:模板里含有逻辑判断
  2. //模板逻辑样式尽可能的绝对分离
  3. //逻辑运算结果需要被复用
  4. const App = {
  5. data(){
  6. return {
  7. studentCount: 1
  8. }
  9. },
  10. template: `
  11. //不建议写法:
  12. <h1>{{studentCount > 0 ? ('学生数:' + studentCount) : '暂无学生'}}
  13. //建议的写法
  14. <h1>{{ studentCountInfo }}
  15. `,
  16. computed: {
  17. studentCountInfo(){
  18. return this.studentCount > 0
  19. ? ('学生数:' + this.studentCount)
  20. : '暂无学生';
  21. }
  22. }
  23. }
  1. //注意:computed对象里是一个getter/setter结构
  2. computed: {
  3. calData: {
  4. get(){...},
  5. set(){...}
  6. }
  7. }

watch属性

侦听器的关注点在数据更新:给数据增加侦听器,当数据更新时,侦听器函数执行

特点:

数据更新时,需要完成什么样的逻辑,如 Ajax数据提交

  1. const app = Vue.createApp({
  2. data(){
  3. return {
  4. a: 'This is my Title'
  5. }
  6. },
  7. computed: {
  8. result(){}
  9. },
  10. watch: {
  11. //侦听computed里的数据:
  12. //可以获取到新老值
  13. //result更新会触发侦听器
  14. result(newValue, oldValue){}
  15. //侦听data里的数据:
  16. a(newValue, oldValue){}
  17. }
  18. });

案例:答题系统

有 4 道题目,点击对应答案的按钮后会显示答案结果的页面

技术:

webpack + vue + express

实现功能:

监听数据发生变化时触发相应的程序

源码地址:

https://gitee.com/kevinleeeee/exam-vue-watch-demo

ClassStyle绑定

操作元素的 class列表和内联样式是数据绑定的一个常见需求。

因为它们都是 attribute,所以我们可以用 v-bind 处理它们:

只需要通过表达式计算出字符串结果即可。

不过,字符串拼接麻烦且易错。因此,在将 v-bind 用于 classstyle 时,表达式结果的类型除了字符串之外,还可以是对象或数组。

  1. //vue 对v-bind:class/style进行了特殊的封装
  2. //形式是比较多的,对象和数组的绑定方式
  3. const MyAlert = {
  4. data() {
  5. return {
  6. title: 'This is my first Alert',
  7. isShow: true,
  8. hasError: true,
  9. alertClassObject: {
  10. show: true,
  11. 'bg-danger': true
  12. }
  13. }
  14. },
  15. computed: {
  16. alertClassObjectComputed() {
  17. return {
  18. show: this.isShow,
  19. danger: this.isShow && this.hasError
  20. }
  21. }
  22. },
  23. template: `
  24. <!--<div
  25. class="my-alert"
  26. :class="{
  27. //加某个样式类名的真假条件
  28. show: isShow,
  29. danger: hasError
  30. }"
  31. >-->
  32. <div
  33. class="my-alert"
  34. :class="alertClassObjectComputed"
  35. >
  36. <header class="header">
  37. <h1>{{title}}</h1>
  38. </header>
  39. </div>
  40. `
  41. }
  1. //vue会在运行时自动检测添加相应的前缀
  2. :style="{display: ['-webkit-box', '-ms-flexbox', 'flex']}"

命名

  1. //6种命名方法:
  2. 1.camelCae 小驼峰命名 thisIsMyVariable
  3. 2.kebab-case 短横线命名法 this-is-my-variable
  4. 3.脊柱命名法 spinal-case train-case
  5. 4.蛇形命名法 snake_case this_is_my_variable
  6. 5.匈牙利命名法 变量 属性+类型 描述 以空字符为结尾的字符串的长整形指针
  7. 6.大驼峰命名法 ThisIsMyVariable

事件处理

事件处理函数的绑定,实际上是原生 JavaScript里绑定事件处理函数,用户行为触发,事件和处理函数进行绑定行为,事件的触发会执行其绑定的处理函数

  1. //vue 绑定写法
  2. v-on="eventType"
  3. v-on:click=""
  4. @click=""
  5. //1.绑定JavaScript表达式(逻辑简单也不推荐)
  6. <button @click="count += 1" ></button>
  7. //2.绑定处理函数(逻辑较为复杂)
  8. <button @click="addCount"></button>
  9. //3.内联绑定处理函数(调用:这里不会执行methods里对应的方法,目的是为了传参)
  10. <button @click="addCount(1)"></button>
  11. //4.多事件处理函数绑定
  12. <button @click="addCount(1), setLog('add', 2)"></button>

问题:vue是如何实现事件绑定?

首先,在 JavaScript里,@click="addCount(1)"默认就会自己执行,但在 vue里不会自动执行,而是先通过模板编译,当填写@click="addCount(1)"时,会返回一个函数传入一个$event参数

  1. function($event){ addCount($event, 2); }

修饰符

事件修饰符@click.once,目的在与把事件处理函数中非纯逻辑的程序分离出去

  • .once只调用一次事件处理,调用一次以后自动移除监听器

  • .prevent阻止默认事件

  • .capture采用捕获

  • .stop阻止事件冒泡

  • .passive拥有不调用Event.preventDefault()

  • v-model.lazyinput+value输入完成失去焦点时,数据改变

  • v-model.number如果无法被 parseFloat解析,就返回原始值/在有 number时,就返回数值

  • v-model.trim过滤掉首尾的空白字符

全局API

Vue.filter

注册或获取全局过滤器。Vue.js允许你自定义过滤器,可被用于一些常见的文本格式化。对视图上的数据绑定的时候的再加工

过滤器可以用在两个地方:双花括号插值和 v-bind 表达式

  1. // 注册
  2. Vue.filter('my-filter', function (value) {
  3. // 返回处理后的值
  4. })
  5. // getter,返回已注册的过滤器
  6. var myFilter = Vue.filter('my-filter')