vue(1) 基础_组件化_模块化
一. 邂逅Vuejs
1.1. 认识Vuejs
- 为什么学习Vuejs
- Vue的读音
- Vue的渐进式
- Vue的特点
- 解耦视图和数据
- 可复用的组件
- 前端路由技术
- 状态管理
- 虚拟DOM
1.2. 安装Vue
- CDN引入
- 下载引入
开发环境 https://vuejs.org/js/vue.js 生产环境 https://vuejs.org/js/vue.min.js
- npm安装
通过webpack和CLI的使用
1.3. Vue的初体验
1.4. Vue中的MVVM
M:Model,数据层 V:View,视图层,面向用户展示信息 VM:VueModel,视图模型层,View和Model层沟通的桥梁,实现数据绑定、数据监听。即Model、View一方发生改变,另一方自动变化
1.5. 创建Vue时, options可以放那些东西
- el: string | HTMLElement,决定之后Vue实例会管理哪一个DOM
- data: Object | Function,Vue实例对应的数据对象
- methods: { [key: string]: Function },定义属于Vue的一些方法
- 生命周期函数
二.插值语法
- mustache语法:展示data中的数据
{{message}}
- v-once:表示元素和组件(组件后面才会学习)只渲染一次,不会随着数据的改变而改变
<div v-once>{{message}}</div>
- v-html:按照HTML格式进行解析
<div v-html='link'></div>
- v-text:作用和Mustache一致
<!-- v-text不够灵活 {{}}用的更多 -->
<h3 v-text="message"></h3>
- v-pre: 跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法
<h3 v-pre>{{message}}</h3>
- v-cloak: vue解析前数据不显示, 之后不会用到
<h3 v-cloak>{{message}}</h3>
三. v-bind
3.1. v-bind绑定基本属性href/src
- v-bind:src
- :href 简写
3.2. v-bind动态绑定class
- 对象语法: 作业 :class='{类名: boolean}'
<h2 class="title" :class="{'active': isActive, 'line': isLine}">Hello World</h2>
- 数组语法:
<h2 class="title" :class="['active’,'line']">Hello World</h2>
3.3. v-bind动态绑定style
- 对象语法:
:style="{color: currentColor, fontSize: fontSize + 'px'}"
- 数组语法:
<div v-bind:style="[baseStyles, overridingStyles]"></div>
一. 计算属性
1.1. 计算属性的本质
- fullname: {set(), get()}
1.2. 计算属性和methods对比
-
计算属性在多次使用时, 只会调用一次.
-
它是有缓存的
-
案例一: firstName+lastName
// 计算属性computed,与methods的区别:有缓存,不必每次重新计算
computed: {
fullName: function () {
// 这是一种简写方式, get方法
return this.message + " " + this.obj.name;
},
// fullName:{
// get:function(){
// return this.message +" "+ this.obj.name;
// },
// set:function(newValue){
// // console.log(newValue)
// }
// }
}
二. 事件监听v-on
简写:@
2.1. 事件监听基本使用
2.2. 参数问题
- btnClick
- btnClick(event):默认event参数
- btnClick(abc, $event):传参注意写法
<div>
<!-- 事件监听v-on,传参问题 -->
<p @click="btnClick">v-on传参:MouseEvent</p>
<p @click="btnClick()">v-on传参:undefined</p>
<p @click="btnClick(123)">v-on传参:123</p>
<!-- 需要参数、又需要event对象的写法 -->
<p @click="btnClickAnother(123,$event)">v-on传参:123+event对象</p>
</div>
2.3. 修饰符
- .stop:阻止冒泡
- .prevent:阻止默认事件
- .enter:监听enter按键
- .once:只监听一次
- .native:使自定义组件可响应原生事件,不局限于自定义事件
<div>
<!-- v-on修饰符 -->
<!-- .stop,阻止内到外冒泡 -->
<div @click="outClick">
<button @click.stop="inClick">按钮</button>
</div>
<!-- .prevent阻止默认事件 -->
<form action="baidu">
<input type="submit" value="提交" @click.prevent="submitBtn" />
</form>
<!-- 监听键盘某个按键点击,这里监听enter建 -->
<input type="text" @keyup.enter="keyUp" />
<!-- .once 只监听一次,用户第一次点击才有效 -->
<button @click.once="inClick">按键</button>
<!-- .native 使自定义组件能够使用原生事件, 如@click.native -->
</div>
三. 条件判断
3.1. v-if/v-else-if/v-else
3.2. 登录小案例
<div>
<!-- v-if、v-else-if和v-else的使用 -->
<div v-if="isShow">v-if的使用</div>
<div v-else>v-else的使用</div>
<button @click="vifBtn">控制v-if</button>
<div>
<div v-if="isUser">
<span for="username">用户账号</span>
<input
type="text"
id="username"
placeholder="请输入用户名"
key="username"
/>
</div>
<div v-else>
<span for="useremail">用户邮箱</span>
<input
type="text"
id="useremail"
placeholder="请输入用户邮箱"
key="email"
/>
</div>
<button @click="switchBtn">切换</button>
</div>
</div>
3.3. v-show
- v-show和v-if区别
两者消失的方式不同,选择看使用频率: v-if条件为false时, 元素不存在于DOM中 v-show, 样式增加 display:none,控制台可查看到对应代码
四. 循环遍历
4.1. 遍历数组
写法:
<span v-for='item in arr'>{{item}}</span>
<span v-for='(item,index) in arr'>{{item}}</span>
4.2. 遍历对象
写法:
- value
- value, key
- value, key, index
4.3. 数组哪些方法是响应式的
响应式方法:push、pop、shift、unshfit、splice:删除、插入、替换 另一种方案,替换:Vue.set(obj,start,target) arr[xx]=yy 不是响应式
五. 书籍案例
略。
六. v-model的使用:表单数据双向绑定
6.1. v-model的基本使用
本质是语法糖:
- v-model => v-bind:value + v-on:input
<input type="text" v-model="message" />
等价于:
<input type="text" :value="message" @input="valueChange" />
valueChange(e){
this.message = e.target.value
}
6.2. v-model和radio/checkbox/select
<!-- 结合radio类型 -->
<label for="male">
<input type="radio" value="男" v-model="sex" />男
</label>
<label for="female">
<input type="radio" value="女" v-model="sex" />女
</label>
<!-- 结合checkbox类型 -->
<label for="agree">
<input type="checkbox" id="agree" v-model="isAgree" />同意协议
</label>
<!-- checkbox多选框 -->
<label :for="item" v-for="item in hobbiesArr">
<input
type="checkbox"
v-model="hobbies"
:value="item"
:id="item"
/>{{item}}
</label>
<!-- 结合select类型使用 -->
<select name="" id="" v-model="selectFruit">
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="梨子">梨子</option>
<option value="火龙果">火龙果</option>
</select>
6.3. 修饰符
- lazy:懒加载
- number:只能输入数字
- trim:去除输入两边空格
<!-- .lazy 懒加载 -->
<input type="text" v-model.lazy="message" />
<!-- .number 只能输入数字 -->
<input type="text" v-model.number="age" />{{age}} {{typeof(age)}}
<!-- .trim 去除输入的两边空格-->
<input type="text" v-model.trim="name" />
七. 组件化开发
7.1. 认识组件化
7.2. 组件的基本使用
组件的使用分成三个步骤(之前):
- 创建组件构造器:Vue.extend({…})的形式(已很少使用)
- 注册组件:Vue.component
- 使用组件
现在一般这样进行注册:
<template id="mycpn">
<div>分离式写法</div>
</template>
<script>
const cpn = {
template:'#mycpn',
data(){return{}},
}
const app = new Vue({
el:'#app',
components:{
cpn, // 局部注册,只能在app实例中使用,vue实例相当于父组件, cpn是子组件
}
})
</script>
7.3. 全局组件和局部组件
局部组件注册如上,全局组件如下:
<template id="mycpn">
<div>分离式写法</div>
</template>
<script>
const cpn = {
template:'#mycpn',
data(){return{}},
}
Vue.component('cpn1',cpn) // 全局注册可在任一vue实例使用
</script>
7.4. 父组件和子组件
如上
7.5. 注册的语法糖
如上,Vue.component(‘cpn’,{…}),这里的对象{…},vue内部中就包含了Vue.extend的相关操作
7.6. 模板的分类写法
- script:
<script type='text/x-template' id='cpn'></script>
- template:
<template id='cpn'></template>
如上例子
7.7. 数据的存放
- 子组件不能直接访问父组件
- 子组件中有自己的data, 而且必须是一个函数.
- 为什么必须是一个函数.
首先若不是,vue会报错;其次,原因在于每次让组件对象都返回一个新的对象,return {…}
7.8. 父子组件的通信
- 父传子: props
基本用法:props可以是数组/对象,若为对象,可设置默认值、数据验证
// 在子组件中有个属性props,可以是数组/对象
props: {
cmessage: String,
cHobby: {
type: Array,
default() {
// 引用类型,需返回函数
return ["篮球"];
},
required: true,
},
},
- 子传父: $emit,自定义事件
methods: {
itemClick(id) {
console.log(id);
// 子组件发射事件, 参数:事件名,参数
this.$emit("xxx", id);
},
},
在vue2.3.0中新增了.sync修饰符,用于简化子组件传值给父组件的方式:
<comp :foo.sync="bar"></comp>
// 会被扩展为
<comp :foo="bar" @update:foo="val => bar = val"></comp>
// 当子组件需要更新foo的值时,需要显式地触发一个更新事件:
this.$emit('update:foo', newValue)
一. 组件化开发
1.1. 父子组件的访问
- 父得到子组件对象:$children(少用)/ $refs(多用)
vue实例有属性$children,表示在实例中注册的子组件对象数组,通过下标访问某个具体子组件对象,因此很少用。$refs用的多,在父子组件中对子组件进行ref标记,如ref=‘aaa’,父组件中可通过this.$refs.aaa得到子组件对象。
<div id='app'>
<cpn ref="aaa"></cpn>
</div>
- 子得到父组件对象:$parent(少用)/$root(获取根组件对象)
开发中不建议使用$parent,因为考虑子组件的复用性,其父组件对象不固定的。造成耦合度很高,不利于复用。
1.2. slot插槽的使用
slot.html slot让组件具有扩展性,预留空间,让父子组件中使用时,有更多自定义性。 抽取共同部分,将不同处作为插槽。
- 基本使用
<slot><button>插槽默认值</button> </slot>
- 具名插槽:多个插槽时进行区分
vue2.6.0+废弃了父组件中slot的写法,slot='right' --> v-slot:right
,注意 v-slot
只能添加在 <template>
上 (只有一种例外情况),v-slot可缩写为v-slot:right --> #right
// 子组件:
<slot name="left"><button>左边</button></slot>
<slot name="middle"><button>中间</button></slot>
<slot name="right"><button>右边</button></slot>
// 父组件
<cpn2>
<span slot="middle">具名插槽</span> // 已废弃
<template v-slot:middle>
<span>具名插槽</span>
</template>
</cpn2>
- 编译的作用域概念
父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。
- 作用域插槽:父组件决定子组件插槽标签展示形式,子组件决定插槽数据
vue2.6.0+版本:slot='dedault' slot-scope='slot' --> v-slot:default='slot'
,多个插槽: v-slot:插槽名=‘数据调用方法名’,可缩写为:v-slot:default='slot' --> #default='slot'
// 子组件
<template id="cpn3">
<div>
<div>作用域插槽:</div>
<slot :mydata="language">
<ul>
<li v-for="item in language">{{item}}</li>
</ul>
</slot>
</div>
</template>
// 父组件
<div>
<cpn3>
// 2.6.0+使用v-slot
<template v-slot:default="slot">
<span>{{slot.mydata.join(' - ')}}</span>
</template>
</cpn3>
<cpn3></cpn3>
</div>
独占默认插槽的缩写语法 解构插槽Prop 动态插槽名:2.6.0新增 具名插槽的缩写:2.6.0新增
二. 前端模块化
2.1. 为什么要使用模块化
- 简单写js代码带来的问题
JS文件过多时,整理顺序麻烦;多人开发命名冲突等;
- 立即执行匿名函数解决命名问题,但代码不可复用
- 自己实现了简单的模块化:在匿名函数中定义对象return出去
- AMD/CMD/CommonJS/ES6 Modules语法:
其中CommonJS在node环境中使用,ES6 Modules在平时开发时使用
CommonJS导入导出:
//A.js
function add(a,b){
return a+b;
}
let obj = {name:'vue'}
// 导出
module.exports = {add, obj} // 用了对象简写形式(es6)
// B.js
let {add} = require('./A.js')
add(5,6);
2.2. ES6中模块化的使用
- export 导出
- import 导入
// A.js
let a = 1;
let b = 2;
let obj = {}
export function add(c,d){return c+d}
export {a,b}
export default obj // 只能存在1个
// B.js
import {a,b} from './A.js'
// or
import myobj from './A.js' // 为默认
// or
import * from './A.js' // 导入全部