VueJs

76 阅读7分钟

Chapter0 初识

MVVM(Model View ViewModel)

Vue的生命周期

生命周期:事物从诞生到消亡的整个过程

ES6补充

列表展示v-for

后面给数组追加元素时,新的元素也可以渲染出来

Chapter1 Vue基础语法

1.2插值操作

Mustache语法

不仅可以直接写变量,也可以写简单的表达式

v-once指令

只在第一次展示数据,当数据发生修改后展示的值不会相应修改

v-html指令

可以将内容转换为html内容输出

v-text指令

可以实现mustache的效果,但是会覆盖原来的文本

v-pre指令

使内容原封不动地展示出来而不做任何解析

<h2>{{message}}</h2>
<h2 v-pre>{{message}}</h2>

v-cloak

在vue解析之前div中有一个v-cloak属性, 直到vue解析,div中v-cloak属性会自动删除

1.3 v-bind

  • 实现动态绑定属性(基本属性:src,href等)
  • 语法糖:v-bind:value="" => :value=""
  • 动态绑定class(对象语法{类名:boolean},数组语法)
  • 动态绑定Style(对象语法{},数组语法)

1.4计算属性computed

获取各种属性,本质上就是一个属性而非函数,因此使用时不需要加括号

setter()和getter()

计算属性其实是一个对象,对象中有setter()和getter()方法 一般情况下没有setter()方法,此时计算属性是一个只读属性 getter()方法的返回值就是计算属性的属性值 因此可以使用语法糖:

fullName(){
    return this.firstName + ' ' + lastName
}

计算属性和methods的对比

计算属性在浏览器中具有缓存,每次浏览器页面发生改变时都会将计算属性与原来的值进行对比:若发生改变则重新调用函数,若未发生改变则无需重新调用函数 因此,计算属性在多次使用时只会调用一次 而methods方法每次都要重新调用整个函数

1.5事件监听

语法糖:v-on:click="method" => @click="method" 在事件监听时,若函数没有参数需要传递则可以省略括号 如果函数需要传入参数而事件监听时省略了小括号,则Vue会将浏览器产生的event对象作为参数传入 方法定义时如果需要同时传入event和其他参数时,可以使用$event手动获取浏览器产生的event对象

修饰符

  1. .stop修饰符可以阻止事件的冒泡
  2. .prevent修饰符可以阻值默认事件的发生
  3. .监听键盘的某个键(如enter键) @keyUp.enter="keyUp"
  4. .once修饰符可以使事件监听的触发函数只触发一次
  5. .native

1.6条件判断

v-if = "Boolean" v-else-if = "Boolean" v-else 根据不同的条件选择不同页面的显示

v-show = "Boolean" v-show 为false时,元素的display属性设置为none 而v-if为false时,元素根本就不会存在在DOM中 因此,当我们需要在显示与隐藏间反复多次进行切换时选用v-show,而如果只需要少次切换时则使用v-if

1.7循环遍历

遍历数组

  1. 仅遍历数组内的元素,而不遍历索引值 v-for="value in arr"
  2. 遍历元素和索引 v-for="(value,index) in arr"

遍历对象

  1. 仅遍历对象内的值 v-for = "value in obj"
  2. 遍历键值对 v-for = "(value,key) in obj"
  3. 遍历键值对和索引 v-for = "(value,key,index) in obj"

数组中哪些方法是响应式的

  1. push() 向数组末端添加元素,可以一次添加多个元素
  2. pop() 删除数组末端元素
  3. shift() 删除数组的第一个元素
  4. unshift() 向数组最前面添加元素,也可以一次添加多个元素
  5. splice(a,b,c) 从第a个元素开始删除b个元素,在a之前添加元素c
  6. sort() 排序
  7. reverse() 反转

Vue.set(要修改的对象,索引值,修改后的值)(响应式) Vue.set(this.arr,0,'bbb')

通过索引值改变元素(非响应式)

1.8书籍购物车案例

<!DOCTYPE html>
<html lang="en"><head>
  <meta charset="UTF-8">
  <title>书籍购物车</title>
  <link rel="stylesheet" href="./style.css">
</head><body>
  <div id="app">
    <div v-if="books.length">
      <table>
        <thead>
          <tr>
            <th></th>
                        <th>书籍名称</th>
                        <th>出版日期</th>
                        <th>价格</th>
                        <th>购买数量</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="(item,index) in books">
                        <td>{{item.id}}</td>
                        <td>{{item.name}}</td>
                        <td>{{item.date}}</td>
                        <td>{{item.price | showPrice}}</td>
                        <td>
                            <button @click="sub(index)" v-bind:disabled="item.count <= 1">-</button> {{item.count}}
                            <button @click="add(index)">+</button>
                        </td>
                        <td>
                            <button @click="removeH(index)">移除</button>
                        </td>
                    </tr>
                </tbody>
            </table>
            <h2>总价格:{{totalPrice | showPrice}}</h2>
        </div>
        <h2 v-else>购物车为空</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script src="./main.js"></script>
</body></html>
const app = new Vue({
    el: '#app',
    data: {
        books: [
            { id: 1, name: '《算法导论》', date: '2006-9', price: 85, count: 1 },
            { id: 2, name: '《UNIX编程艺术》', date: '2006-2', price: 59, count: 1 },
            { id: 3, name: '《编程珠玑》', date: '2008-10', price: 39, count: 1 },
            { id: 4, name: '《代码大全》', date: '2006-3', price: 128, count: 1 },
        ],
​
    },
    methods: {
        getFinalPrice(price) {
            return '¥' + price.toFixed(2)
        },
        add(index) {
            this.books[index].count++
        },
        sub(index) {
            this.books[index].count--
        },
        removeH(index) {
            this.books.splice(index, 1)
        }
    },
    filters: {
        showPrice(price) {
            return '¥' + price.toFixed(2)
        }
    },
    computed: {
        totalPrice() {
            let totalPrice = 0
            for (let i of this.books) {
                totalPrice += i.price * i.count
            }
            return totalPrice
        }
    }
})
table {
    border: 1px solid #e9e9e9;
    border-collapse: collapse;
    border-spacing: 0;
}
​
th,
td {
    padding: 8px 16px;
    border: 1px solid #e9e9e9;
    text-align: center;
}
​
th {
    background-color: #f7f7f7;
    color: #5c6b77;
    font-weight: 600;
}

1.9双向绑定

1.9.1基本使用与本质

v-model

<!-- 使用 v-model实现双向绑定 -->
<input type="text" v-model="message">
<!-- <input type="text" :value="message" @input="message = $event.target.value"> -->

1.9.2v-model和radio

具有相同name属性的选项互斥,而给选项绑定相同的v-model也可以达到相同的效果 通过给v-model设初值可以实现设置选项的默认值(在html中使用cheked属性),如不需设置默认值则将初值设为空字符串

1.9.3v-model和checkbox

  • 通过在input外添加label,并将label的for与input的id设置为相同,可实现点击文字也可触发点击选框的效果
  1. checkbox单选框 v-model值为布尔值
  2. checkbox多选框 v-model值为数组

1.9.4v-model和select

  1. 选择一个 v-model值为字符串
  2. 选择多个 v-model值为数组

1.9.5修饰符

  1. .lazy修饰符可以使数据不再实时绑定,而是在敲回车或失去焦点时才绑定
  2. .number修饰符可以使v-model的赋值类型为Number而非String //input中键入数字 type="number"
  3. .trim修饰符可以将v-model的空格删除

Chapter2 组件化开发

组件的使用分三个步骤:

  1. 创建组件构造器
  2. 注册组件
  3. 使用组件

2.1全局组件和局部组件

2.2父组件和子组件

2.3组件注册的语法糖

2.4模板的分离写法

script

template

2.5数据的存放

  • 子组件不能直接访问父组件的数据
  • 子组件有自己的data,且必须是一个函数
  • 为什么必须是一个函数?

组件之间相互影响

2.6父子组件的通信

父传子pros

子传父$emit

2.7项目

npm install npm run serve

2.8父子组件的访问

2.9slot

3模块化

3.1为什么要使用模块化

3.2ES6中模块化的使用

  • export
  • import

Chapter4 Webpack

4.1什么是 webpack

4.2webpack起步

4.3webpack的loader

4.4webpack配置Vue

4.5webpack的plugin

4.6搭建本地服务器

4.7配置文件的分离

Chapter5 Vue CLI详解

Command-Line Interface译为命令行界面,俗称脚手架

5.2 CLI2初始化项目的过程

5.3 CLI2生产的目录结构的解析

Chapter6 vue-router

🌏扩展笔记:

  1. 什么是前端渲染什么是后端渲染?
  1. 后端渲染阶段:jsp(java server page)/php 在后端通过各种技术直接将页面渲染完成再返回给前端并直接展示 (一个页面有自己的网址,就是url)前端将url发送到服务器,服务器对url(通过正则)进行匹配,然后通过控制器处理,生成 HTML和css代码返回给前端 后端路由:后端处理url和页面之间关系的路由
  1. 前后端分离阶段:随着Ajax出现,有了前后端分离的开发模式 后端只提供API来返回数据,前端通过Ajax获取数据,并通过JS渲染页面 当获取到url时,先去静态资源服务器中请求html+css+js代码,当执行js时发现api请求,再去服务器请求api相关资源,再根据这些资源对页面进行渲染 前端渲染:浏览器中显示的大部分内容都由前端js代码在浏览器中执行,最终渲染出来的网页
  1. 单页面富应用阶段(SPA--Single Page web Application):在前后端分离的基础上添加了前端路由 整个页面只有一个HTML页面,当url发生改变时整个页面不刷新,不再向服务器请求新的资源 前端路由:映射url->页面
  1. 如何改变页面的url却不使页面发生刷新(不向服务器发送新的请求)
  1. url的hash 直接修改hash
  2. history方法 history.pushState({},'','home'), history.back(), history.replaceState({},'','home'), history.go(-1), history.forward()
  1. 网址含义

🌏 URL:协议//localhost:端口/路径?查询 Scheme//host:port/path?query#fragment

vue-router基于路由和组件

router-link

tag="button" 设置router-link的样式为按钮(默认为 a标签) to="/home" 设置点击后url改变的值 点击时按钮会增添一个router-link-active类 class的名字可以通过class-active属性修改

代码跳转路由

动态路由

**this.$route.params.userId

路由的懒加载

打包时打包三个文件 app.js 自己写的代码 manifest.js 底层支撑的代码 vendor.js 第三方代码

懒加载:用到时再加载 将不同路由由不同组件分割成不同的代码块,当路由被访问时才加载对应组件 懒加载的方式:

  1. const Home = resolve =>{}...
  2. AMD写法 const About = resolve => require(['../components/About.vue'],resolve)
  3. ES6写法 const Home = () => import('../components/Home.vue')

嵌套路由

实现嵌套路由的步骤:

  1. 创建对应的子组件,并且在路由映射中配置对应的子路由
  2. 在组件内部使用标签

参数传递

传递参数主要有两种类型: params和query

params的类型

配置路由格式: /router/:id 传递的方式: 在path后跟上对应的值 传递后形成的路径: /router/123,/touter/abc

query的类型(传递对象)

配置路由格式: /router,也就是普通配置 传递的方式: 对象中使用query的key作为传递方式 传递后形成的路径: /router?id=123,/router?id=abc

router和route

任何一个组件里的this.router就是router对象,是VueRouter的实例,具有push()等方法this.router就是router对象,是VueRouter的实例,具有push()等方法 this.route是当前处于活跃的路由对象,具有参数params,query等

导航守卫

监听导航栏的变化

  1. 全局守卫
//设置导航(前置)守卫
router.beforeEach((to, from, next) => {
    //从from跳转到to时执行(跳转前执行)
    document.title = to.matched[0].meta.title
    next()
})
​
//设置导航(后置)守卫
router.afterEach((to, from) => {
    //从from跳转到to时执行(跳转后执行)
    document.title = to.matched[0].meta.title
    next()
})
  1. 路由独享守卫 在路由配置时直接定义beforeEnter守卫 进入之前(跳转之前之后,跳转之后之前)
  2. 组件内的守卫

keep-alive

keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态或避免被重新渲染 router-view也是一个组件,如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存

Chapter7 Vuex详解

Vuex是一个专为Vue.js应用程序开发的状态管理模式

  • 把需要多个组件共享的变量全部存储在一个对象里
  • 然后将这个对象放在顶层的Vue实例里,让其他组件可以使用

🌏哪些状态需要管理呢?

  • 用户的登录状态、用户名称、头像、地理位置信息等
  • 商品的收藏、购物车中的物品等
  • 响应式,需要共享的

Chapter8 网络封装axios

Vue中发送网络请求有非常多的方式

  1. 传统的Ajax是基于XHR (配置和调用方式非常混乱)
  2. jQuery-Ajax (Vue中不需要jQuery,得不偿失)
  3. Vue-resourse (Vue2.x之后已不再维护)
  4. 🌟axios

Chapter9 项目实践

  1. 划分目录结构 assets(资源) imgs css common(公共的常量和方法) const.js utils.js components(公共的组件): common(其他项目里也会用到的组件) content(仅在当前项目中会用到的公共组件) network() router store view(各个主要的视图)
  2. css文件的引入

vue2中组件不能直接监听事件,需要添加.native

<back @click.native="backClick"></back>

vue3中则可以直接监听

不使用v-bind绑定的props会传递字符串,绑定之后则可以传递各种类型的数据

事件总线$bus

防抖节流

  • 防抖debounce
debounce(func, delay) {
      let timer = null;
      return function (...args) {
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
          func.apply(this, args);
        }, delay);
      };
    }
  • 节流throttle

tab-control吸顶效果

  1. 必须直到滚动到多少时开始有吸顶效果(获取到tab-control的offsetTop

    • 但不能直接在mounted中获取该值,在mounted中的值并没有将图片高度计算在内
    • 因此要监听HomeSwiper中img的加载完成
    • 加载完成后发出事件,并在Home.vue中获取正确的值
    • 为了不让HomeSwiper多次发出事件,可以使用一个isLoad变量记录状态
  2. 利用两个tabControl组件实现“假动画”

Home离开时状态记录

  1. keep-alive

  2. 让Home中内容保持

    • 离开时保存一个位置信息saveY

跳转至商品详情页

  1. 创建新组件,绑定路由并设置点击跳转事件
  2. this.iid = this.$route.params.iid
  3. 搭建详情页

搭建详情页

导入navbar

  • 导入DetailNavBar DetailNavBar 中导入NavBar
  • 设置title与back

请求数据及轮播图展示

  1. Detail也keep-alive,要使用exclude将其剔除,则需要为组件设置name属性

混入mixin

toast弹窗

Chapter10 项目部署

服务器:一台没有显示器的电脑,24小时开机为用户提供服务 下载nginx 最新stable版本

将自己的电脑作为服务器

git add .

git commit -m '初始化项目'

git push

面试题

Vue响应式原理
  • 数据更新页面跟着更新其实不是理所当然的
  1. app.message修改数据,Vue内部是如何监听message数据改变的?

Object.defineProperty -> 监听对象属性的改变

  1. 当数据发生改变,Vue是如何通知哪些人页面发生刷新?

发布订阅者模式

\