Vue


此笔记根据 B站狂神视频教程整理

推荐优秀笔记

MVVM

MVVM(Model-View-ViewModel)是一种软件架构设计模式,源自于经典的MVC(Model-View-Controller)模式。MVVM的核心是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用,其作用如下:

  • 该层向上与视图层进行双向数据绑定

  • 向下与Model层通过接口请求进行数据交互

为什么要使用MVVM

MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处

  • 低耦合:视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变
  • 可复用:你可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑
  • 独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计
  • 可测试:界面素来是比较难于测试的,而现在测试可以针对ViewModel来写

Vue.js就是一个MVVM的实现者,他的核心就是实现了DOM监听与数据绑定

  • Model:模型层,在这里表示JavaScript对象
  • View:视图层,在这里表示DOM(HTML操作的元素)
  • ViewModel:连接视图和数据的中间件,Vue.js就是MVVM中的ViewModel层的实现者
  • 在MVVM架构中,不允许数据和视图直接通信,只能通过ViewModel来通信,而ViewModel就是定义了一个 Observer观察者
  • ViewModel能够观察到数据的变化,并对视图对应的内容进行更新
  • ViewModel能够监听到视图的变化,并能够通知数据发生改变

基本语法




    
    Title




{{message}}

Yes

No

A

B

Other

  • {{item.message}}

  • {{item.message}}----{{index}}
  • vue 绑定事件

    学习vue我们必须之到它的7个属性,8个方法,以及7个指令。787原则

    • el
      • 用来指示vue编译器从什么地方开始解析vue的语法,可以说是一个占位符
    • data
      • 用来组织从vlew中抽象出来的属性,可以说将视图的数据抽象出来存放在data中
    • template
      • 用来设置模板,会替换页面元素,包括占位符
    • methods
      • 放置页面中的业务逻辑,js方法一般都放置在methods中
    • render
      • 创建真正的Virtual Dom
    • computed
      • 用来计算
    • watch
      • watch:function(new,old)(}
      • 监听data中数据的变化
      • 两个参数,一个返回新值,一个返回旧值

    Vue.js是一个MVVM框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是Vue.js的精髓之处了。

    我们所说的数据双向绑定,是对于UI控件来说的,非UI控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用vuex,那么数据流也是单项的,这时就会和双向数据绑定有冲突。

    
    
    
        
        Title
    
    
    
    
    
    
    
    输入的文本: {{message}}

    输入的文本: {{message2}}
    性别:

    选择的是:{{msg}}

    下拉框:

    选择的是:{{selected}}

    image-20220515001912828

    vue 组件

    
    
    
        
        Title
    
    
    
    
    
    
    {{}}

    image-20220515004412958

    Axios

    Axios是一个开源的可以用在浏览器端和 NodeJs的异步通信框架,她的主要作用就是实现AJAX异步通信,其功能特点如下:

    • 从浏览器中创建 XMLHttpRequests
    • 从node.js创建http 请求
    • 支持Promise API[JS中链式编程]
    • 拦截请求和响应
    • 转换请求数据和响应数据
    • 取消请求
    • 自动转换JSON数据
    • 客户端支持防御XSRF(跨站请求伪造)

    GitHub

    中文文档

    Vue的生命周期

    Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载DOM、渲染→更新→渲染、卸载等一系列过程,我们称这是Vue的生命周期。通俗说就是Vue实例从创建到销毁的过程,就是生命周期

    img

    data_for_demo04.json

    {
      "name":"Kite is learning vue",
      "url": "https://www.cnblogs.com/kitelee/",
      "page": 1,
      "isNonProfit": true,
      "address": {
        "street": "都司大街",
        "city": "山东",
        "country": "中国"
      },
      "links": [
        {
          "name": "bilibili",
          "url": "https://space.bilibili.com/352587345"
        },
        {
          "name": "Kite blog",
          "url": "https://www.cnblogs.com/kitelee/"
        },
        {
          "name": "百度",
          "url": "https://www.baidu.com/"
        }
      ]
    }
    

    demo04.html

    
    
    
        
        Title
    
    
    
    {{info.name}}
    {{info.address.city}}
    blog

    image-20220515104511990

    计算属性

    
    
    
        
        Title
    
    
    
    

    currentTime1: {{currentTime1()}}

    currentTime2: {{currentTime2}}

    currentTime1: 1652584254589
    demo05.html?_ijt=jqe5hqud369udvvvlu3nmhefc9&_ij_reload=RELOAD_ON_SAVE:33 currentTime2: 1652584254589
    vm.currentTime1()
    demo05.html?_ijt=jqe5hqud369udvvvlu3nmhefc9&_ij_reload=RELOAD_ON_SAVE:26 currentTime1: 1652584265557
    1652584265557
    vm.currentTime1()
    demo05.html?_ijt=jqe5hqud369udvvvlu3nmhefc9&_ij_reload=RELOAD_ON_SAVE:26 currentTime1: 1652584268781
    1652584268781
    vm.currentTime2
    1652584254589
    vm.currentTime2
    1652584254589
    vm.message = "changed"
    demo05.html?_ijt=jqe5hqud369udvvvlu3nmhefc9&_ij_reload=RELOAD_ON_SAVE:26 currentTime1: 1652584296158
    demo05.html?_ijt=jqe5hqud369udvvvlu3nmhefc9&_ij_reload=RELOAD_ON_SAVE:33 currentTime2: 1652584296158
    'changed'
    vm.currentTime1()
    demo05.html?_ijt=jqe5hqud369udvvvlu3nmhefc9&_ij_reload=RELOAD_ON_SAVE:26 currentTime1: 1652584301845
    1652584301845
    vm.currentTime2
    1652584296158
    vm.currentTime2
    1652584296158
    vm.message = "changed"
    'changed'
    vm.currentTime2
    165258429615
    
    • methods:定义方法,L调用方法使用currentTime10,需要带括号
    • computed:定义计算属性,调用属性使用currentTime2,不需要带括号;this.message是为了能够让currentTime2观察到数据变化而变化
    • 如何在方法中的值发生了变化,则缓存就会刷新!可以在控制台使用 vm,message=“changed”,改变下数据的值,再次测试观察效果

    image-20220515111528910

    计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约系统开销

    插槽 slot

    v-bind 可以简写为

    v-on 可以简写为 @

    
    
    
        
        Title
    
    
    
    
    

    image-20220515115424490

    自定义事件

    JSsplice()方法是修改Array的“万能方法”,它可以从指定的素引开始删除若干元素,然后再从该位置添加若干元素:

    var arr = ['Microsoft','Apple', 'Yahoo', 'AOL', 'Excite', 'Oracle'];
    //从索引2开始删除3个元素,然后再添加两个元素
    arr.splice(2,3,'Google','Facebook');//返回删除的元素 ['Yahoo','AoL','Excite']
    arr; 	// ['Microsoft','Apple','Google','Facebook','Oracle']
    //只删除,不添加:
    arr.splice(2, 2); // ['Google','Facebook']
    arr; // ['Microsoft','Apple','Oracle']
    //只添加,不剧被素复时
    arr.splice(2,0,'Google','Facebook');//返回[],因为没有删除任何元素
    arr; // ['Mierosoft','Apple','Google','Facebook','oracle']
    
    
    
    
        
        Title
    
    
    
    
    

    image-20220515141422497

    image-20220515141545816

    vue-cli

    # 初次安装需要步骤
    npm install cnpm -g
    (cnpm)npm install vue-cli -g
    

    image-20220515144419468

    vue init webpack myvue
    

    image-20220515144905787

    cd myvue
    npm install
    npm audit fix (--force)
    
    # **
    
    npm run dev
    

    IDEA 打开myvue

    # npm 版本太高,导致失败则安装低版本 npm
    npm install npm@6.14.10 -g
    
    vue init webpack myvue
    cd myvue
    npm install
    npm audit fix
    npm run dev
    

    成功后:

    image-20220515154601880

    webpack

    本质上,webpack是一个现代JavaScript应用程序的静态模块打包器(module bundler).当webpack处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle

    Webpack是当下最热门的前端资源模块化管理和打包工具,它可以将许多松散耦合的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分离,等到实际需要时再异步加载。通过loader转换,任何形式的资源都可以当做模块,比如CommonsJS、AMD、ES6、CSS、JSON、CoffeeScript、LESS等;

    伴随着移动互联网的大潮,越来越多的网站已经从网页模式进化到了WebApp模式。它们运行在现代浏览器里,使用HTML5、CSS3、ES6等新的技术来开发丰富的功能,网页已经不仅仅是完成浏览器的基本需求;WebApp通常是一个SPA(单页面应用),每一个视图通过异步的方式加载,这导致页面初始化和使用过程中会加载越来越多的JS代码,这给前端的开发流程和资源组织带来了巨大挑战

    CommonsJS
    服务器端的NodeJS遵循CommonsJS规范,该规范核心思想是允许模块通过require方法来同步加载所需依赖的其它模块,然后通过exports或module.exports来导出需要暴露的接口。

    优点

    • 服务器端模块便于重用
    • NPM中已经有超过45万个可以使用的模块包
    • 简单易用

    缺点:

    • 同步的模块加载方式不适合在浏览器环境中,同步意味着阻塞加载,浏览器资源是异步加载的
    • 不能非阻塞的并行加载多个模块

    实现:

    • 服务端的NodeJS
    • Browserify,浏览器端的CommonsJS实现,可以使用NPM的模块,但是编译打包后的文件体积较大
    • modules-webmake,类似Browserify,但不如Browserify 灵活
    • wreq,Browserify的前身

    AMD

    Asynchronous Module Definition规范其实主要一个主要接口 define(id?,dependencies?,factory);它要在声明模块的时候指定所有的依赖dependencies,并且还要当做形参传到factory中,对于依赖的模块提前执行。

    优点

    适合在浏览器怀境中异步加载模块
    可以并行加载多个模块

    缺点

    提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不畅
    不符合通用的模块化思维方式,是一种妥协的实现

    CMD ...

    ES6

    EcmaScript6标准增加了JavaScript语言层面的模块体系定义。ES6模块的设计思想,是尽量静态化,使编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonsJS和AMD模块,都只能在运行时确定这些东西。

    import "jquery";
    export function doStuff() {}
    module "localModule" {}
    

    优点

    • 容易进行静态分析
    • 面向未来的EcmaScript标准

    缺点

    • 原生浏览器端还没有实现该标准
    • 全新的命令,新版的NodeJS才支持

    实现 : Babel

    WebPack是一款模块加载器兼打包工具,它能把各种资源,如JS、JSX、ES6、SASS、LESS、图片等都作为模块来处理和使用。

    npm install webpack -g
    npm install webpack-cli -g
    

    创建webpack.config.js配置文件

    • entry:入口文件,指定WebPack用哪个文件作为项目的入口
    • output:输出,指定WebPack把处理完成的文件放置到指定路径
    • module:模块,用于处理各种类型的文件
    • plugins:插件,如:热更新、代码重用等
    • resolve:设置路径指向
    • watch:监听,用于设置文件改动后直接打包
    • 建立空文件夹,IDEA打开

    • 建立子文件夹 modules

    • 新建 hello.js 和 main.js

    • // hello.js
      // 暴露一个方法
      exports.sayHi = function () {
          document.write("

      Kite is learning

      "); }; // ------------------------------------- // main.js var hello = require("./hello"); hello.sayHi();
    • 新建 webpack.config.js (与 modules 同目录 )

    • module.exports = {
          entry: './modules/main',
          output: {
              filename: "./js/bundle.js"
          }
      }
      
    • 打开IDEA terminal 输入 webpack

    image-20220515164346609

    • 新建 index.html

    • 
      

    vue-router

    Vue Router是Vue.js官方的路由管理器。它和Vue.js的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:

    • 嵌套的路由/视图表
    • 模块化的、基于组件的路由配置
    • 路由参数、查询、通配符
    • 基于Vue.js过渡系统的视图过渡效果
    • 细粒度的导航控制
    • 带有自动激活的CSS class的链接
    • HTML5历史模式或hash模式,在IE9中自动降级
    • 自定义的滚动条行为

    基于前文 vue-cli 进行测试学习;先查看node_modules中是否存在 vue-router,vue-router是一个插件包,所以需要用npm/cnpm来进行安装的。

    npm install vue-router --save-dev
    

    如果在一个模块化工程中使用它,要通过Vue.use()明确地安装路由功能:

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    Vue.use(VueRouter);
    

    测试

    image-20220515165850443

    terminal

    npm install vue-router --save-dev 	
    

    新建router/index.js

    import Vue from 'vue'
    import Router from 'vue-router'	// 导入 router 
    
    import Main from '../components/Main'		// 新建 components/Main.vue
    import Content from '../components/Content'	// 新建 components/Content.vue
    
    Vue.use(Router);	// 显示引用
    
    export default new Router({
      routes: [
        {
          path: '/content',
          component: Content	
        }, {
          path: '/main',
          component: Main
        }
      ]
    });
    

    main.js中

    import Vue from 'vue'
    import App from './App'
    import router from './router'
    
    Vue.config.productionTip = false
    
    new Vue({
      el: '#app',
      router,
      components: { App },
      template: ''
    })
    

    App.vue

    
    
    
    
    
    
    

    terminal

    npm install
    npm run dev
    npm run dev
    

    image-20220516091613278

    vue-router 由于版本不一致,导致引用失败

    import VueRouter from 'vue-router'

    cnpm install vue-router@3.1.3 --save-dev

    可以成功

    import VueRouter from 'vue-router'

    cnpm install vue-router --save-dev

    则失败

    原因:import VueRouter from 'vue-router' ,默认自动跳转到 vue-router 的 index.d.ts

    新版本会直接跳转到 vue-router.d.ts

    image-20220516083326928

    vue+elementUI

    初始化

    vue init webpack hello-vue
    cd hello-vue
    npm install vue-router --save-dev	# cnpm install vue-router@3.1.3 --save-dev
    npm i element-ui -S
    
    npm install
    npm install sass-loader node-sass --save-dev	
    # cnpm install less@3.9.0 less-loader@4.1.0 --save-dev
    
    npm run dev
    

    新建router/index.js

    import Vue from 'vue'
    import Router from 'vue-router'
    
    import Main from '../views/Main'
    import Login from '../views/Login'
    
    
    Vue.use(Router);
    
    export default new Router({
      routes: [
        {
          path: '/login',
          component: Login
        }, {
          path: '/main',
          component: Main
        }
      ]
    });
    

    main.js中

    import Vue from 'vue'
    import App from './App'
    import router from './router'
    
    import ElementUI from 'element-ui'
    import 'element-ui/lib/theme-chalk/index.css'
    
    Vue.config.productionTip = false
    
    Vue.use(ElementUI);
    
    new Vue({
      el: '#app',
      router,
      render: h => h(App)
    })
    

    新建 views/login.vue 和 views

    
    
    
    
    
    
    

    App.vue

    
    
    
    

    npm install 会安装 package.json 里对应版本的包,调整版本修改 package.json 即可

    components 存放功能性的组件

    views 存放视图性的组件

    路由嵌套

    新建views/user/Profile.vue 和 views/user/List.vue

    
    export default {
      name: "UserProfile"
    }
    
    
    export default {
      name: "UserList"
    }
    

    在 router/index.js 中添加路由

    import Vue from 'vue'
    import Router from 'vue-router'
    
    import Main from '../views/Main'
    import Login from '../views/Login'
    
    import UserList from '../views/user/List'
    import UserProfile from '../views/user/Profile'
    
    Vue.use(Router);
    
    export default new Router({
      routes: [
        {
          path: '/login',
          component: Login
        }, {
          path: '/main',
          component: Main,
          children: [
            {
              path: '/user/profile',
              component: UserProfile
            }, {
              path: '/user/list',
              component: UserList
            }
          ]
        }
      ]
    });
    

    对 Main.vue 套用模板

    
    
    
    
    
    
    

    image-20220516135103431

    参数传递

    修改 Main.vue

    
    
    
    个人信息
    
    个人信息2
    

    修改路由 index.js

    // {path: '/user/profile',component: UserProfile}
    
    // 方式 1
    {
        path: '/user/profile/:lee/:kite',
        name: 'UserProfileLee',
        component: UserProfile
    }
    
    // 方式 2
    {
        path: '/user/newProfile/:age/:gender',
        name: 'NewUserProfileLee',
        component: NewUserProfile,
        props: true
    }
    

    profile.vue

    
    
    
    
    
    
    
    
    
    
    
    

    注意:

    • 要在路由的index 里给传参的链接 增加 name 属性(不传参也可加)
    • 传递的参数遵循 restful 风格
    • Main.vue 要绑定传参的路由以及传递的参数
    • 传递的参数不能直接写在
    • 注意两种方式的区别

    重定向

    修改 Main.vue

    
        回到首页
    
    

    修改路由 index.js

    {path: '/goHome', redirect: '/main'}
    

    与参数传递进行比较 重定向 对现有路径进行跳转不需要导入路由、不需要新建 vue

    
    

    修改路由

    path: '/main/:username',
    component: Main,
    props: true
    

    Main.vue

       
    
    
      
        

    Kite's Second-hand Book Trade in School

    {{username}}

    image-20220516164318379

    404

    路由模式有两种

    hash:路径带#符号,如http://localhost/#/login

    history:路径不带#符号,如http://localhost/login

    通过 index.js 来修改模式

    export default new Router({
      mode: 'history',		// mode
      routes: [
        {
          path: '/login',
          component: Login
        },
        ...
      ]
    });
    

    404

    新建 NotFound.vue

    404,你找的页面不见了...

    修改路由 index.js

    import NotFound from '../views/NotFound'
    
    path: '*',
    component: NotFound
    

    路由钩子

    Profile.vue

    • beforeRouteEnter -- 进入之路由前
    • beforeRouteLeave -- 进入路由之后
    
    

    beforeRouteEnter: (to, from, next)

    • to:路由将要跳转的路径信息
    • from:路径跳转前的路径信息
    • next:路由的控制参数
      • next()跳入下一个页面
      • next('/path')改变路由的跳转方向,使其跳到另一个路由
      • next(false),返回原来的页面
      • next((vm)=>{})仅在beforeRouteEnter中可用,vm是组件实例

    main.js

    import axios from 'axios'
    import VueAxios from 'vue-axios'
    
    // 如果没有安装则 cnpm install --save axios vue-axios
    
    
    Vue.use(VueAxios, axios);
    

    在 static 文件夹下新建 static/mock/data.json

    {
      "name":"Kite is learning vue",
      "url": "https://www.cnblogs.com/kitelee/",
      "page": 1,
      "isNonProfit": true,
      "address": {
        "street": "都司大街",
        "city": "山东",
        "country": "中国"
      },
      "links": [
        {
          "name": "bilibili",
          "url": "https://space.bilibili.com/352587345"
        },
        {
          "name": "Kite blog",
          "url": "https://www.cnblogs.com/kitelee/"
        },
        {
          "name": "百度",
          "url": "https://www.baidu.com/"
        }
      ]
    }
    

    image-20220517001236228

    前端得到了数据