Vue

Vue是什么

Vue是一套用于构建用户界面的渐进式JavaScript框架。作者尤雨溪。

Vue.js - The Progressive JavaScript Framework | Vue.js

Vue.js - 渐进式 JavaScript 框架 | Vue.js

https://github.com/vuejs

IDE:Visual Studio Code或WebStorm

Vue的特点

渐进式:Vue可以自底向上逐层的应用:简单应用只需一个轻量小巧的核心库;复杂应用可以引入各式各样的Vue插件。

组件化:页面某个模块对应的html、css、js可以封装成一个vue文件,提高了代码复用率,且易于维护。

声明式编码:无需操作DOM,提高开发效率。

DOM复用:使用虚拟DOM + Diff算法,尽量复用DOM。

MVVM

MVVM(Model-View-ViewModel)是脱胎于MVC的架构模式,其核心ViewModel提供对视图View和数据Model的双向数据绑定,保证它们的数据一致性:

使用DOM Listeners将View层DOM元素的变化更新到Model层;

使用Directives(指令)将Model层的变化更新到View层DOM元素。

前后端技术栈对比

语言

框架

工具

项目构建

依赖管理

前端

JavaScript:es6,7,8...

JQuery、Vue、React

webstorm,vscode

webpack,gulp

npm

后端

Java:jdk8,9,10,11...

Spring、SpringMVC

idea,eclipse

maven,gradle

maven

安装

官网文档提供了3种安装方式:

  1. 直接 script 引入本地 vue 文件。需要通过官网下载 vue 文件

https://cn.vuejs.org/v2/guide/installation.html下载:vue.js(开发版)或vue.min.js(生产版)

  1. 通过 script 引入 CDN 代理。需要联网,生产环境可以使用这种方式

对于制作原型或学习,可以这样使用最新版本:<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>

对于生产环境,推荐链接到一个明确的版本号和构建文件:<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>

  1. 通过 npm 安装。这种方式也是官网推荐的方式,需要 nodejs 环境。
    1. 新建文件夹 hello-vue,并使用 vscode 打开
    2. 打开vscode终端,使用npm init -y初始化npm,项目下会生成:

package.json文件:用来记录项目信息和项目依赖。

    1. 使用 npm install vue@2安装vue2,项目下会生成:

package-lock.json文件:指定依赖的具体版本,保证开发副本环境一致

node_modules目录:用来存放用包管理工具下载安装的包,该目录下有个子目录vue。

本示例vue2使用npm安装。

Hello World

  1. 声明一个要被Vue所控制的DOM(View)并指定id,在要渲染内容的位置使用插值表达式{{}}占位。
  2. 创建Vue实例(包含Model的ViewModel),使用el属性绑定指定id的DOM,在data属性中定义要渲染的内容。
  3. vscode代码编辑页面右键-》Open with Live Server,可看到效果,打开网页控制台,给Vue实例属性改值(本例vm.name="vue2"),可实时更改页面展示。

Vue对象中,用el绑定元素,用data封装数据,用methods封装方法。

视图中,使用模板语法引用模型中的数据或方法。

注意:视图v-on指令中的this指向Window对象,模型methods中的this指向Vue对象。

Chrome安装Vue的开发者工具

Chrome 应用商店直接翻墙安装Vue.js devtools,然后重新vscode代码编辑页面右键-》Open with Live Server,开发者工具上会多出一个“Vue”标签。

注意如果要使用Vue.js devtools,引入的vue脚本应为开发版。

关闭productionTip:

<body>
<div id="app">
    <h1>hello {{name}}</h1>

    <h1>hello {{getName()}}</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            name: "vue"
        },
        methods: {
            getName(){
                return this.name;
            }
        }
    });
</script>
</body>

    • Directives

内容渲染指令:{{}} / v-text / v-html /v-once

{{}}插值表达式:在元素中的某一位置采用纯文本的方式渲染数据

v-text:将数据采用纯文本方式填充其空元素中

v-html:将数据采用 HTML 语法填充其空元素中

v-once:执行一次性插值,当数据改变时,插值处的内容不会继续更新

插值表达式有插值闪烁问题,解决方法:

首先,在差值语法所在的标签处加上v-cloak指令

然后,在css中设置v-cloak的属性为display为none:

<style type="text/css">[v-cloak]{display: none;}</style>

视图:

模型:

v-text:<span v-text="hello"></span> <br />

v-html:<span v-html="hello"></span>

data: {

    hello: "<h1>大家好</h1>"

},

属性绑定指令:v-bind:

语法:如<img v-bind:src="...">简写为<img :src="...">

如果绑定的值是null或undefined,那么该属性将从渲染的元素上移除。

如果绑定class属性或style属性,属性对象的key可用驼峰式(camelCase)或烤串式(kebab-case)表示,短横分隔时需加引号。

绑定Class

对象语法:视图表示为对象,模型负责定义是否需要某class

视图:

模型:

渲染为:

<div :class="{ active: isActive, 'text-danger': hasError }"></div>

data: {

  isActive: true,

  hasError: false

}

<div class="active"></div>

数组语法:视图表示为数组,模型负责定义class名

视图:

模型:

渲染为:

<div :class="[activeClass, errorClass]"></div>

data: {

  activeClass: 'active',

  errorClass: 'text-danger'

}

<div class="active text-danger"></div>

混合写法:视图表示为数组中嵌套对象,模型负责定义class名或是否需要某class

视图:

模型:

渲染为:

<div :class="[{ active: isActive }, errorClass]"></div>

data: {

  errorClass: 'text-danger',

  isActive: true

}

<div class="active text-danger"></div>

绑定Style

对象语法:视图表示为对象,模型负责定义style属性值

视图:

模型:

渲染为:

<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

data: {

  activeColor: "red",

  fontSize: 30

}

<div style="color: red; font-size: 30px"></div>

数组语法:视图表示为数组,模型负责定义style对象

视图:

模型:

渲染为:

<div :style="[colorStyle, fontSizeStyle]"></div>

data: {

  colorStyle: {

    color: "red"

  },

  fontSizeStyle: {

    fontSize: "30px"

  }

}

<div style="color: red; font-size: 30px"></div>

双向绑定指令v-model

v-model指令用在表单元素(<input>、<select>、<textarea>)和Vue自定义组件(components)中:

文本类型的<input>和<textarea>元素会绑定value属性并侦听input事件

<input type="checkbox">、<input type="radio">和<select>会绑定选中项的value属性并侦听change事件

v-model的修饰符:

.number 自动将用户的输入值转为数值类型

.trim 自动过滤用户输入的首尾空白字符

.lazy 在 chang 时而非 input 时更新

视图:

模型:

<input type="checkbox" v-model="language" value="Java" />Java<br />

<input type="checkbox" v-model="language" value="PHP" />PHP<br />

<input type="checkbox" v-model="language" value="Swift" />Swift<br />

<p>你选择了:{{language.join(',')}}</p>

data: {

language: []

}

事件绑定指令: v-on:

v-on:指令用来监听DOM事件,并在事件触发时执行对应的JavaScript。

语法:v-on:<事件名>="<js片段或函数名>"

简写:@<事件名>="<js片段或函数名>"

事件修饰符

在事件处理程序中调用`event.preventDefault()`或`event.stopPropagation()`是非常常见的需求。尽管我们可以在方法中实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理DOM事件细节。

.prevent 阻止默认行为

.stop 阻止事件冒泡

.capture 使用事件捕获模式(以捕获模式触发当前的事件处理函数)

.once 只执行一次

.self 只有在event.target是当前元素自身时触发事件处理函数(冒泡或捕获的都不执行)

.passive 向浏览器表明了不想阻止事件的默认行为

视图:

模型:

<div style="border: 1px solid red; padding: 20px;" @click="sayHellow('外层DIV')">
    <div style="border: 1px solid blue; padding: 20px;" @click="sayHellow('内层DIV')">
        <a href="危险网站地址" @click.prevent.stop="sayHellow('危险网站')">点击领取!</a>
    </div>
</div>

methods: {
    sayHellow(name) {
        alert("Hellow, I am " + name);
    }
}

按键修饰符

按键别名:.enter、.tab、.esc、.space、.up、.down、.left、.right、.delete (捕获 Delete 和 Backspace 两个按键)

系统修饰符:.ctrl、.alt、.shift、.meta

准确的修饰符:.exact

视图:

模型:

<input type="text" v-model="num"

       @keyup.up="num+=1"
       @keyup.down="num-=1"
       @keyup.up.ctrl="num+=10"
       @keyup.down.ctrl="num-=10">

data: {
    num: 0
}

鼠标按键修饰符:

.left、.right、.middle

条件渲染指令(分支渲染指令):v-if / v-else-if / v-else /v-show

v-if:当条件判断为true时,所在的元素才会被渲染。(条件首次为true时所在元素才渲染,条件切换时涉及的元素都会销毁或重建)

v-show:当条件判断为true时,所在的元素才会被显示。(条件无论如何所在元素都会渲染,条件为true时所在元素展示(CSS display))

如果需要频繁切换,使用v-show(无切换开销)

如果在运行时绑定条件很少改变,使用v-if(更低的初始渲染开销)

v-if支持在<template>元素上使用,这只是一个不可见的包装器元素,最后渲染的结果并不会包含这个<template>元素。

v-show不支持在<template>元素上使用。

视图:

模型:

<button v-on:click="random=Math.random()">点我呀</button>
<span>{{random}}</span>
<h1 v-if="random >= 0.75">看到我啦?!v-if >= 0.75</h1>
<h1 v-else-if="random > 0.5">看到我啦?!v-else-if > 0.5</h1>
<h1 v-else-if="random > 0.25">看到我啦?!v-else-if > 0.25</h1>
<h1 v-else>看到我啦?!v-else</h1>

data: {
    random: 1
}

列表渲染指令(循环渲染指令)v-for

使用 v-for 指令基于一个数组来渲染一个列表

v-for渲染数组

语法:(item[, index]) in items

          item :元素

          index :索引

          items :需要遍历的数组

v-for渲染对象

遍历顺序取决于对该对象调用 Object.keys() 的返回值顺序。

语法:(value[, name[, index]]) in object

          value :属性值

          name :键

          index :索引

          items :需要循环的对象

通过 key 管理状态:

当列表的数据变化时,默认情况下,vue 会尽可能的复用已存在的 DOM 元素,从而提升渲染的性能;

但这种默认的性能优化策略,会导致有状态的列表无法被正确更新。

为了给 vue 一个提示,以便它能跟踪每个节点的身份,从而在保证有状态的列表被正确更新的前提下,提升渲染的性能;

此时,需要为每项提供一个唯一的key属性。

key 的注意事项:

key 的类型只能是 Number/String

key 值必须具有唯一性

建议循环的列表有一个属性当 key(该属性的值在此列表中唯一)

不使用索引当 key

建议使用 v-for 指令时一定要指定 key 的值

最佳实践:

如果 items 是数组,可以使用 index 作为:key

如果 items 是对象数组,可以使用 item.id 作为:key

结合v-if有条件遍历:

v-if的优先级比v-for低,所以可以每次迭代时判断是否展示。

视图:

模型:

<ul>
    <li v-for="(user, index) in users" :key="user.name" v-if="user.gender == '女'">
        概览:{{index}}. {{user.name}} - {{user.gender}} - {{user.age}}<br />
        详情:<span v-for="(v, k, i) in user" :key="i">{{i}}: {{k}}={{v}}; </span>
    </li>
</ul>

data: {
    users: [
        { name: '范冰冰', gender: '女', age: 21 },
        { name: '刘德华', gender: '', age: 24 },
        { name: '刘亦菲', gender: '女', age: 18 },
        { name: '周星驰', gender: '', age: 25 }
    ]
}

    • computed、侦听watch、过滤器filters

计算属性computed

某些属性的值是依赖其他属性值实时计算出来的,我们可以利用计算属性来计算,只要依赖的属性发生变化,就会重新计算这个属性。

示例(暂不考虑精度和负数问题):

侦听watch

watch 可以让我们监控属性值的变化。从而做出相应的反应。

过滤器filters

过滤器不改变真正的`data`,而只是改变渲染的结果,并返回过滤后的版本。在很多不同的情况下,过滤器都是有用的,比如尽可能保持 API 响应的干净,并在前端处理数据的格式。

局部过滤器:注册在当前Vue实例中,只有当前实例能用;

全局过滤器:在创建Vue实例之前定义全局过滤器,所有实例可用。

当全局过滤器和局部过滤器重名时,会采用局部过滤器。

视图中使用管道符号后接过滤器名来过滤属性值:<属性> | <过滤器名>

视图:

模型:

<div id="app">
    <ul>
        <li>西游记:价格{{xyjPrice}},
            出版年份:{{xyjPubDate | pubDateFilter}},
            数量:<input type="number" v-model="xyjNum"></li>
        <li>水浒传:价格{{shzPrice}},
            出版年份:{{shzPubDate | pubDateFilter}},
            数量:<input type="number" v-model="shzNum"></li>
        <li>总价:{{totalPrice}}</li>
        {{msg}}
    </ul>
</div>

<script src="./node_modules/vue/dist/vue.js"></script>
<script>
    Vue.filter('pubDateFilter', function (pubDate) {
        return pubDate.substr(0,4);
    })
    let vm = new Vue({
        el: "#app",
        data: {
            xyjPrice: 56.73,
            shzPrice: 47.98,
            xyjPubDate: "2019-06-01",
            shzPubDate: "2020-06-01",
            xyjNum: 1,
            shzNum: 1,
            msg: ""
        },
        computed: {
            totalPrice() {
                return this.xyjPrice * this.xyjNum + this.shzPrice * this.shzNum;
            }
        },
        watch: {
            xyjNum(newVal, oldVal) {
                if (newVal >= 3) {
                    this.msg = "西游记没有更多库存了";
                    this.xyjNum = 3;
                } else {
                    this.msg = "";
                }
            }
        },
        filters: {
            pubDateFilter(pubDate) {
                return pubDate.substr(0,4);
            }
        }
    })
</script>

不同的页面可能会有相同的部分,例如相同的头部导航。我们可以将相同的部分做成组件进行复用。

组件与Vue实例:

在 vue 里,所有的 vue 实例都是组件,组件其实也是一个 Vue 实例,因此它在定义时也会接收:data、methods、生命周期函数等,不同的是:

  1. 组件没有el属性,因为要复用,所以不与元素绑定。
  2. 组件增加了template属性,因为组件渲染染需要html模板
  3. 组件data必须是一个函数,不再是一个对象,因此每个实例可以维护一份被返回对象的独立的拷贝,否则不同地方使用的是同一份数据。

关于组件名:

组件名为多个单词组成时,可使用烤串式命名(kebab-case),也可使用驼峰式命名(CamelCase),驼峰式命名需要脚手架支持

组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。

可以使用name配置项指定组件在开发者工具中呈现的名字(默认展示为大驼峰式)。

关于组件标签:

组件标签可使用自闭包形式,但不用使用Vue脚手架时,会导致后续组件不能渲染。

<body>
<div id="app">
    <!--使用全局组件,可以任意复用多次-->
    <global-counter></global-counter>
    <global-counter></global-counter>
    <global-counter></global-counter>
    <!--使用局部组件,可以任意复用多次-->
    <local-counter></local-counter>
    <local-counter></local-counter>
    <local-counter></local-counter>

</div>
<script src="../node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
    // 定义全局组件,两个参数:1,组件名称。2,组件参数
    Vue.component("global-counter", {
        name: "global-counter",
        template: '<button @click="count++">你点了全局组件 {{ count }} 次</button>',
        data() {
            return {
                count: 0
            }
        }
    });
    // 定义局部组件,结构与创建全局组件时传递的第二个参数一致
    //完整写法:const 组件名 = Vue.extend(options) {...}
    const localCounter = {
        name: "local-counter",
        template: '<button @click="count++">你点了局部组件 {{ count }} 次</button>',
        data() {
            return {
                count: 0
            }
        }
    };
    let app = new Vue({
        el: "#app",
        // 注册局部组件
        components: {
            "local-counter": localCounter //如果左右名称相同,可直接单写名称
        }
    })
</script>
</body>

生命周期是指实例对象从构造函数开始执行(被创建)到被GC垃圾回收销毁的整个存在时期,在生命周期中被自动调用的函数叫作生命周期函数,又叫钩子函数。不同的时期会有不同的钩子函数,可以利用不同时期的钩子函数去完成不同的操作。

生命周期总体流程:创建-》挂载[-》更新]-》销毁

所有生命周期钩子函数的 this 上下文都会自动指向当前调用它的组件实例。注意:避免用箭头函数来定义生命周期钩子,因为如果这样的话你将无法在函数中通过 this 获取组件实例。

生命周期与钩子函数

模型与视图

钩子函数使用场景

new Vue()

初始化默认事件&默认生命周期函数

beforeCreate()

不可访问datamethods

真实DOM中变量未赋值

可增加一些loading事件

初始化数据(注入&校验)

data、methods加载

created()

可访问data、methods、computed、watch

真实DOM中变量未赋值

无法访问$el

可结束loading事件,完成一些初始化,实现函数自执行等。

未挂载DOM,若在此阶段进行DOM操作一定要放在Vue.nextTick()的回调函数中。

如果未指定el选项,等待调用vm.$mount(el)

如果指定了template选项,将template编译到render函数中,如果未指定template选项,将el父级DOM作为template编译

编译template填充data,生成虚拟DOM

beforeMount()

真实DOM中变量未赋值

创建vm.$el并用其替换el所指向的视图

虚拟DOM替换真实DOM

mounted()

真实DOM中变量赋值

可以访问$el、$ref

开启定时器、发送网络请求、订阅消息、绑定自定义事件

挂载完毕

当data被修改:

beforeUpdate()

data已更新

真实DOM未更新

虚拟DOM重新渲染并应用更新

data更新到真实DOM

updated()

真实DOM已更新,与data保持一致

当调用vm.$destroy()函数:

beforeDestroy()

可以访问data、methods、过滤器、指令

关闭定时器、取消订阅消息、解绑自定义事件

解除绑定、销毁子组件以及自定义事件监听器

销毁完毕

destroyed()

无法访问data、methods、过滤器、指令

    • vue-cli模块化开发

使用Vue脚手架初始化项目

vue-cli俗称Vue脚手架,cli是Command-Line Interface的缩写。

Vue脚手架用于快速生成一个vue的项目模板,作用类似于maven。

全局安装 webpack(以前执行过就不用执行了):

npm install webpack -g

全局安装 vue 脚手架(以前执行过就不用执行了):

npm install -g @vue/cli-init

如果安装时点了鼠标导致安装暂停,按下键盘即可恢复安装。

用 webpack 模板初始化 vue 项目:

vue init webpack <项目名称>

启动 vue 项目:

npm run dev

项目的 package.json 中有 scripts,代表我们能运行的命令。

项目结构

├─build 项目构建(webpack)相关代码

├─config 配置目录

├─node_modules 依赖目录

├─src 源代码

│  ├─assets 存放静态资源

│  ├─components 存放组件

│  ├─router 路由配置

│  │  App.vue 项目入口文件,汇总所有组件

│  └  main.js 项目核心文件

├─static 存放静态资源

├─test 测试目录

│  .xxx文件 一些配置文件,如语法配置、git忽略配置等

│  index.html 首页入口文件

│  package-lock.json 包版本控制文件

│  package.json 应用包配置文件

└  README.md 项目说明文档

运行流程

n 进入页面首先加载 index.html 和 main.js 文件。

n main.js 导入了一些模块【vue、app、router】,并且创建 vue 实例,关联 index.html页面的<div id=”app”>元素。使用了 router,导入了 App 组件。并且使用<App/>标签引用了这个组件

n 第一次默认显示 App 组件。App 组件有个图片和<router-view>,所以显示了图片。

但是由于<router-view>代表路由的视图,默认是访问/#/路径(router 路径默认使用HASH 模式)。在 router 中配置的/是显示 HelloWorld 组件。

n 所以第一次访问,显示图片和 HelloWorld 组件。

n 我们尝试自己写一个组件,并且加入路由。点击跳转。需要使用<router-linkto="/foo">Go to Foo</router-link>标签

Vue 单文件组件

Vue 单文件组件模板有三个部分:

<template>:编写模板

<script>:Vue实例配置

<style>:样式

    • element-ui快速开发

安装element-ui

npm i element-ui

在 main.js 中引入 element-ui

import ElementUI from 'element-ui'

import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI)

将 App.vue 改为 element-ui 中的后台布局

添加测试路由、组件,测试跳转逻辑

(1) 、参照文档 el-menu 添加 router 属性

(2) 、参照文档 el-menu-item 指定 index 需要跳转的地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值