vue基本概念
vue是什么?
- 是一套用于构建用户界面的 渐进式框架
什么是渐进式?
- 逐渐进步,想用什么就用什么,不必全部使用
什么是库和框架
- 库:封装的属性或方法
- 框架:拥有自己的规则和元素,比库更强大
什么是MVVM?
MVVM通过数据双向绑定让数据自动地双向同步 不再需要操作DOM
- M: 模型(Model):对应 data 中的数据 -
(data里定义) - V: 视图(View):模板 -
(HTML页面) - VM: 视图模型(ViewModel):Vue实例对象 -
(vue.js源码)
图解:
- V(修改视图) -> M(数据自动同步)
- M(修改数据) -> V(视图自动同步)
@vue/cli 脚手架
- 全局安装@vue/cli包
npm i @vue/cli -g
- @vue/cli是vue官方提供的一个全局模块包,用于快速创建脚手架项目
@vue/cli 创建项目启动服务
1.创建项目
//vue create是命令, vuecli-demo是文件夹名
vue create vuecli-demo
- 项目不能带 大写字母,中文和特殊符号
2.选择模板
- 可以上下箭头选择, 弄错了ctrl+c停止创建重来
-
根据自己的需求选择对应的版本,按住电脑上下键选择,敲回车
-
如下界面就成功了
-
进入脚手架项目下, 启动内置更新本地服务器
cd vuecil-demo
npm run serve
//或
yarn serve
-
你会看到如下界面
@vue/cli 目录和代码分析
vuecil-demo //项目目录
├── node_modules // 项目依赖的第三方包
├── public // 静态文件目录
├── favicon.ico // 浏览器小图标
└── index.html // 单页面的html文件(网页浏览的是它)
├── src // 业务文件夹
├── assets // 静态资源
└── logo.png // vue的logo图片
├── components // 组件目录
└── HelloWorld.vue // 欢迎页面vue代码文件
├── App.vue // 整个应用的根组件
└── main.js // 入口js文件
├── .gitignore //git提交忽略配置
├── babel.config.js // babel配置
├── package.json // 依赖包列表
├── README.md // 项目说明
└── yarn.lock // 项目包版本锁定和缓存地址
- 主要文件及含义
node_modules //都是下载的第三方包
public/index.html – //浏览器运行的网页
src/main.js – //webpack打包的入口文件
src/App.vue – //vue项目入口页面
package.json – //依赖包列表文件
@vue/cli 自定义配置
- @vue/cli用的vue.config.js, 在src下配置
/* 覆盖webpack的配置 */
module.exports = {
devServer: { // 自定义服务配置
open: true, // 自动打开浏览器
port: 3000
},
lintOnSave:false //关闭eslint检查
}
- eslint: 代码的检查工具,一种规范,例如:多个空格,或者声明的变量未使用都会报错,自己写一些小的demo或者初学者建议关闭它,不然你会怀疑人生
Vue中有2种数据绑定的方式
- 单向绑定(v-bind):数据只能从data流向页面。
- 双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data 注意:
1.双向绑定一般都应用在表单类元素上(如:input、select等)
2.v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。
Vue指令
插值表达式
-
语法
{{ 表达式 }} -
在 DOM 标签中,直接插入内容
<template>
<div>
<h1>{{ msg }}</h1>
<h2>{{ obj.name }}</h2>
<h3>{{ obj.age > 18 ? '成年' : '未成年' }}</h3>
</div>
</template>
<script>
export default {
// data 里面专门用来声明变量
data() { // 格式固定, 定义vue数据之处
return { // key相当于变量名
msg: "hello, vue",
obj: {
name: "小vue",
age: 5
}
}
}
}
</script>
- DOM 中插值表达式赋值, vue的变量必须在data里声明
v-bind: ----单项数据绑定
单向绑定(v-bind):数据只能从data流向页面
-
给 DOM 标签属性设置 vue 变量的值
-
语法:
v-bind:属性名="vue变量" -
简写:
:属性名="vue变量"
<!-- vue指令-v-bind属性动态赋值 -->
<a v-bind:href="url">我是a标签</a>
<img :src="imgSrc">
v-model:----双向数据绑定
-
把value属性和vue数据变量, 双向绑定到一起
-
语法:
v-model="vue数据变量" -
双向数据绑定
-
数据变化 -> 视图自动同步
-
视图变化 -> 数据自动同步
-
重点:
-
双向绑定一般都应用在表单类元素上(如:input、select等)
-
遇到复选框, v-model的变量值
-
非数组 - 关联的是复选框的checked属性
-
数组 - 关联的是复选框的value属性
-
<div>
<!--
v-model:是实现vuejs变量和表单标签value属性, 双向绑定的指令
-->
<div>
<span>用户名:</span>
<input type="text" v-model="username" />
</div>
<div>
<span>密码:</span>
<input type="password" v-model="pass" />
</div>
<div>
<span>来自于: </span>
<!-- 下拉菜单要绑定在select上 -->
<select v-model="from">
<option value="北京市">北京</option>
<option value="南京市">南京</option>
<option value="天津市">天津</option>
</select>
</div>
总结:
- 特别注意: v-model, 在input[checkbox]的多选框状态
- 变量为非数组, 则绑定的是checked的属性(true/false) - 常用于: 单个绑定使用
- 变量为数组, 则绑定的是他们的value属性里的值 - 常用于: 收集勾选了哪些值
v-model修饰符
语法:
-
v-model.修饰符="vue数据变量"
-
.number 以parseFloat转成数字类型
-
.trim 去除首尾空白字符
-
.lazy 在change时触发而非inupt时
-
<template>
<div>
<div>
<span>年龄:</span>
<input type="text" v-model.number="age">
</div>
<div>
<span>人生格言:</span>
<input type="text" v-model.trim="motto">
</div>
<div>
<span>自我介绍:</span>
<textarea v-model.lazy="intro"></textarea>
</div>
</div>
</template>
v-text和v-html
- 更新DOM对象的innerText/innerHTML
语法:
- v-text="vue数据变量"
- v-html="vue数据变量"
<template>
<div>
<p v-text="str"></p>
<p v-html="str"></p>
</div>
</template>
<script>
export default {
data() {
return {
str: "<span>我是一个span标签</span>"
}
}
}
</script>
区别:
- v-text把值当成普通字符串显示
- v-html把值当成标签进行解析显示
v-show和v-if
-
控制标签的隐藏或出现
-
语法:
- v-show="vue变量"
- v-if="vue变量"
-
原理
- v-show 用的display:none隐藏 (频繁切换使用)
- v-if 直接从DOM树上移除
-
高级
- v-else使用
<template>
<div>
<h1 v-show="isOk">v-show的盒子</h1>
<h1 v-if="isOk">v-if的盒子</h1>
<div>
<p v-if="age > 18">我成年了</p>
<p v-else>还得多吃饭</p>
</div>
</div>
</template>
<script>
export default {
data() {
return {
isOk: true,
age: 15
}
}
}
</script>
v-for
-
列表渲染, 所在标签结构, 按照数据数量, 循环生成
-
语法
- v-for="(值, 索引) in 目标结构"
- v-for="值 in 目标结构"
-
目标结构:
- 可以遍历数组 / 对象 / 数字 / 字符串 (可遍历结构)
-
注意:
v-for的临时变量名不能用到v-for范围外
<template>
<div id="app">
<div id="app">
<!-- v-for 把一组数据, 渲染成一组DOM -->
<!-- 口诀: 让谁循环生成, v-for就写谁身上 -->
<p>学生姓名</p>
<ul>
<li v-for="(item, index) in arr" :key="item">
{{ index }} - {{ item }}
</li>
</ul>
<p>学生详细信息</p>
<ul>
<li v-for="obj in stuArr" :key="obj.id">
<span>{{ obj.name }}</span>
<span>{{ obj.sex }}</span>
<span>{{ obj.hobby }}</span>
</li>
</ul>
</div>
</template>
v-on:----事件处理
-给标签绑定事件
-
语法
- v-on:事件名="要执行的==少量代码=="
- v-on:事件名="methods中的函数"
- v-on:事件名="methods中的函数(实参)"
-
简写: @事件名="methods中的函数"
<!-- vue指令: v-on事件绑定-->
<p>你要买商品的数量: {{count}}</p>
<button v-on:click="count = count + 1">增加1</button>
<button v-on:click="addFn">增加1个</button>
<button v-on:click="addCountFn(5)">一次加5件</button>
<button @click="subFn">减少</button>
<script>
export default {
// ...其他省略
methods: {
addFn(){ // this代表export default后面的组件对象(下属有data里return出来的属性)
this.count++
},
addCountFn(num){
this.count += num
},
subFn(){
this.count--
}
}
}
</script>
v-on修饰符
语法:
-
@事件名.修饰符="methods里函数"
- .stop - 阻止事件冒泡
- .prevent - 阻止默认行为
- .once - 程序运行期间, 只触发一次事件处理函数
<template>
<div @click="fatherFn">
<!-- vue对事件进行了修饰符设置, 在事件后面.修饰符名即可使用更多的功能 -->
<button @click.stop="btn">.stop阻止事件冒泡</button>
<a href="http://www.baidu.com" @click.prevent="btn">.prevent阻止默认行为</a>
<button @click.once="btn">.once程序运行期间, 只触发一次事件处理函数</button>
</div>
</template>
<script>
export default {
methods: {
fatherFn(){
console.log("father被触发");
},
btn(){
console.log(1);
}
}
}
</script>
v-on按键修饰符
语法:
- @keyup.enter - 监测回车按键
- @keyup.esc - 监测返回按键
动态class
- 用v-bind给标签class设置动态的值
语法:
- :class="{类名: 布尔值}"
<template>
<div>
<!-- 语法:
:class="{类名: 布尔值}"
使用场景: vue变量控制标签是否应该有类名
-->
<p :class="{red_str: bool}">动态class</p>
</div>
</template>
<script>
export default {
data(){
return {
bool: true
}
}
}
</script>
<style scoped>
.red_str{
color: red;
}
</style>
总结: 就是把类名保存在vue变量中赋予给标签
动态style
-
给标签动态设置style的值 语法
-
:style="{css属性: 值}"
<template>
<div>
<!-- 动态style语法
:style="{css属性名: 值}"
-->
<p :style="{backgroundColor: colorStr}">动态style</p>
</div>
</template>
<script>
export default {
data(){
return {
colorStr: 'red'
}
}
}
</script>
总结: 动态style的key都是css属性名
filters----过滤器
- 过滤器就是一个 函数,只能用在, 插值表达式和v-bind表达式
注意点:
-
要定义到
filters节点下,本质是一个函数 -
在过滤器函数中, 一定要有 return 值
-
在过滤器的形参中,可以获取到 “管道符” 前面待处理的那个值
-
如果 全局过滤器和局部过滤器名字一致,此时按照 就近原则,调用的是局部过滤器
-
语法示例:
1.全局
-
每个 .vue 组件都可以使用
- Vue.filter("过滤器名称",function()
2.局部
-
只能在自己的 .vue 组件中使用
- filters:{ "过滤器名称"(){}
}
<template>
<div>
<p>原来的样子: {{ msg }}</p>
<!--
语法: {{ 值 | 过滤器名字 }}
-->
<p>使用翻转过滤器: {{ msg | reverse }}</p>
<p :title="msg | toUp">鼠标长停</p>
</div>
</template>
<script>
export default {
data(){
return {
msg: 'Hello, Vue'
}
},
filters: {
toUp (val) {
return val.toUpperCase()
}
}
}
</script>
全局注册最好在main.js中注册, 一处注册到处使用
watch : 侦听器
- 可以侦听data/computed属性值改变
侦听器格式
-
方法格式的侦听器
- 缺点1:无法在刚进入页面的时候,自动触发
- 缺点2:如果侦听的是一个对象,对象的属性发生了变化,不会触发侦听器
-
对象格式的侦听器
- 好处1:可以通过 immediate : true,让侦听器自动触发
- 好处2:可以通过 deep :true,开启深度监听对象每个属性的变化
-语法:
watch: {
"被侦听的属性名" (newVal, oldVal){
}
}
- 代码示例
<template>
<div>
<input type="text" v-model="name">
</div>
</template>
<script>
export default {
data(){
return {
name: ""
}
},
// 目标: 侦听到name值的改变
/*
语法:
watch: {
变量名 (newVal, oldVal){
// 变量名对应值改变这里自动触发
}
}
*/
watch: {
// newVal: 当前最新值
// oldVal: 上一刻值
name(newVal, oldVal){
console.log(newVal, oldVal);
}
}
}
</script>
侦听器-深度侦听和立即执行
- 侦听复杂类型, 或者立即执行侦听函数
- 语法:
watch: {
"要侦听的属性名": {
immediate: true, // 立即执行
deep: true, // 深度侦听复杂类型内变化
handler (newVal, oldVal) {
}
}
}
-代码示例
<template>
<div>
<input type="text" v-model="user.name">
<input type="text" v-model="user.age">
</div>
</template>
<script>
export default {
data(){
return {
user: {
name: "",
age: 0
}
}
},
// 目标: 侦听对象
/*
语法:
watch: {
变量名 (newVal, oldVal){
// 变量名对应值改变这里自动触发
},
变量名: {
handler(newVal, oldVal){
},
deep: true, // 深度侦听(对象里面层的值改变)
immediate: true // 立即侦听(网页打开handler执行一次)
}
}
*/
watch: {
user: {
handler(newVal, oldVal){
// user里的对象
console.log(newVal, oldVal);
},
deep: true,
immediate: true
}
}
}
</script>
总结: immediate立即侦听, deep深度侦听, handler固定方法触发
computed:计算属性
-
一个数据, 依赖另外一些数据计算而来的结果
-
特点:
- 定义的时候,要定义为 方法
- 在使用计算属性时候,当普通的属性使用即可
-
好处:
- 实现了代码的复用
- 只要计算属性中依赖的数据源变化了,计算属性会自动重新求值
-
原理:
底层借助了Objcet.defineproperty方法提供的getter和setter
-
语法示例:
//简写 computed:{ "计算属性"(){ } } // 完整写法 computed:{ // 自定义函数名称 "计算属性名":{ set(val){ // }, get(){ // } } -
注意点:
-
计算属性的值有缓存
-
计算属性 一定要写return
-
如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变
-
还在更新中