荐 vue基础及高级用法(一)
程序员文章站
2022-09-14 11:43:07
1. 插值表达式{{xxx}}的形式,可以是值,也可以是表达式(不能是 js 语句,比如if、for) var app = new Vue({ el: '#app', data: { msg: 'Hello Vue!', ok: true }})展示效果2. 指...
{{msg}}
{{ok? '1':'2'}}
1. 插值表达式
{{xxx}}的形式,可以是值,也可以是表达式(不能是 js 语句,比如if、for)
<div id="app">
<p>{{msg}}</p>
<p>{{ok? '1':'2'}}</p>
</div>
var app = new Vue({
el: '#app',
data: {
msg: 'Hello Vue!',
ok: true
}
})
展示效果
2. 指令
v-cloak 指令 :直到编译结束显示
<div v-cloak>
{{ message }}
</div>
[v-cloak] {
display: none;
}
v-text 指令 :用于更新 html 标签里的内容
<div id="app">
<p v-text="msg"></p>
<!-- 和下面的一样 -->
<p>{{msg}}</p>
</div>
var app = new Vue({
el: '#app',
data: {
msg: 'message'
}
})
效果展示
v-html 指令 :用于更新并解析 html 标签(不安全)
在网站上动态渲染任意 HTML 是非常危险的,因为容易导致 XSS 攻击。只在可信内容上使用 v-html
效果展示
<div id="app">
<p v-html="msg"></p>
</div>
var app = new Vue({
el: '#app',
data: {
msg: '<span style="color:red">红色字体</span>'
}
})
v-bind 指令 :动态属性绑定
<div id="app">
<p v-bind:id="pid">动态属性 id</p>
<p :id="aid">简写形式</p>
</div>
var app = new Vue({
el: '#app',
data: {
pId: 'pid',
aId: 'aid'
}
})
class与style
<div id="app">
<p :class="{ black: isBlack, yellow: isYellow }">使用 class</p>
<p :class="[black, yellow]">使用 class (数组)</p>
<p :style="styleData">使用 style</p>
</div>
var app = new Vue({
el: '#app',
data() {
return {
isBlack: true,
isYellow: true,
black: 'black',
yellow: 'yellow',
styleData: {
fontSize: '40px', // 转换为驼峰式
color: 'red',
backgroundColor: '#ccc' // 转换为驼峰式
}
}
}
})
v-if、v-else-if、v-else 指令 :有条件地渲染元素
<div id="app">
<p v-if="type === 'a'">A</p>
<p v-else-if="type === 'b'">B</p>
<p v-else-if="type === 'c'">C</p>
<p v-else>other</p>
</div>
var app = new Vue({
el: '#app',
data() {
return {
type: 'a'
}
}
})
v-show 指令 :有条件地控制css display显示或隐藏元素
<div id="app">
<p v-show="type === 'a'">A by v-show</p>
<p v-show="type === 'b'">B by v-show</p>
</div>
var app = new Vue({
el: '#app',
data() {
return {
type: 'a'
}
}
})
v-if 与 v-show 的使用场景
频繁切换,使用 v-show 较好;
运行时条件很少改变,则使用 v-if 较好。
v-for 指令 :循环渲染元素
- 不要把 v-if 和 v-for 同时用在同一个元素上。
<div id="app">
<p>遍历数组</p>
<ul>
<li v-for="(item, index) in listArr" :key="item.id">
{{index}} - {{item.id}} - {{item.title}}
</li>
</ul>
<p>遍历对象</p>
<ul >
<li v-for="(val, key, index) in listObj" :key="key">
{{index}} - {{key}} - {{val.title}}
</li>
</ul>
</div>
var app = new Vue({
el: '#app',
data() {
return {
flag: false,
listArr: [
{ id: 'a', title: '标题1' }, // 数据结构中,最好有 id ,方便使用 key
{ id: 'b', title: '标题2' },
{ id: 'c', title: '标题3' }
],
listObj: {
a: { title: '标题1' },
b: { title: '标题2' },
c: { title: '标题3' },
}
}
}
})
为什么要有key,且不用index(即数组的下标)来作为key。
虚拟dom中,diff算法会根据sel
和key
来判断节点是否可以复用。
v-on 指令 :绑定监听事件
- event 是原生的。
- 事件被挂载到当前元素,和 DOM 事件一样。
用 vue 绑定的事件,组建销毁时会自动解绑。
自己绑定的事件,需要自己销毁!!!
<div id="app">
<p>{{num}}</p>
<button v-on:click="increment1">+1</button>
<button @click="increment1">简写形式</button>
<button @click="increment2(2, $event)">+2</button>
</div>
var app = new Vue({
el: '#app',
data() {
return {
num: 0
}
},
methods: {
increment1(event) {
console.log(event) // 是原生的 event 对象
console.log(event.target) // 注意,事件是被注册到当前元素的,和 React 不一样
this.num++
},
increment2(val, event) {
this.num = this.num + val
},
loadHandler() {
// do some thing
}
},
mounted() {
window.addEventListener('load', this.loadHandler)
},
beforeDestroy() {
//【注意】用 vue 绑定的事件,组建销毁时会自动被解绑
// 自己绑定的事件,需要自己销毁!!!
window.removeEventListener('load', this.loadHandler)
}
})
v-model 指令 :表单数据的双向绑定
修饰符
- .lazy - 取代 input 监听 change 事件
- .number - 输入字符串转为有效的数字
- .trim - 输入首尾空格过滤
表单用法
<div id="app">
<p>输入框: {{name}}</p>
<input type="text" v-model.trim="name"/>
<input type="text" v-model.lazy="name"/>
<input type="text" v-model.number="age"/>
<p>多行文本: {{desc}}</p>
<textarea v-model="desc"></textarea>
<!-- 注意,<textarea>{{desc}}</textarea> 是不允许的!!! -->
<p>复选框 {{checked}}</p>
<input type="checkbox" v-model="checked"/>
<p>多个复选框 {{checkedNames}}</p>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<p>单选 {{gender}}</p>
<input type="radio" id="male" value="male" v-model="gender"/>
<label for="male">男</label>
<input type="radio" id="female" value="female" v-model="gender"/>
<label for="female">女</label>
<p>下拉列表选择 {{selected}}</p>
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<p>下拉列表选择(多选) {{selectedList}}</p>
<select v-model="selectedList" multiple>
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
</div>
var app = new Vue({
el: '#app',
data() {
return {
name: '双越',
age: 18,
desc: '自我介绍',
checked: true,
checkedNames: [],
gender: 'male',
selected: '',
selectedList: []
}
}
})
拓展:v-model实现原理
- v-model的本质是一个语法糖。
- v-model在组件中不建议使用,自行设计即可。
<input v-model="sth" />
第一行的代码其实只是第二行的语法糖
<input v-bind:value="sth" v-on:input="sth = $event.target.value" />
然后第二行代码还能简写成这样:
<input :value="sth" @input="sth = $event.target.value" />
如果是复选框
<input type="checkbox" :checked="status" @change="status = $event.target.checked" />
原理:每当输入框内容发生变化时,就会触发oninput,把最新的value传递给 绑定的值。
v-slot 指令 :插槽,通过父组件决定子组件模板显示
普通插槽
father 模板:
<child>
<p>yy</p>
</child>
child 模板:
<div>
<P>Hello</P>
<slot>父组件没有提供内容的默认值</slot>
</div>
最终的效果相当于
<div>
<P>Hello</P>
<p>yy</p>
</div>
具名插槽
父组件在 <template>
元素上使用 v-slot
<body-content>
<template v-slot:header>
<!-- v-slot 缩写 -->
<!-- <template #header> -->
<div class="header">header</div>
</template>
<template v-slot:footer>
<div class="footer">footer</div>
</template>
</body-content>
子组件通过 name 属性,定义 的名字
<div>
<slot name="header"></slot>
<div class='content'>content</div>
<slot name="footer"></slot>
</div>
v-slot 只能添加在 <template> 上,以下情况例外
当只有默认插槽时,可以把 v-slot 直接用在组件上
<current-user v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</current-user>
作用域插槽
父组件用子组件的数据填充插槽
<div id="app">
<current-user>
<template v-slot:default="slotProps">
子组件传递的姓名{{ slotProps.user }} 年龄{{ slotProps.age}}
</template>
</current-user>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('current-user', {
template: `
<span>
<slot v-bind:user="user" age="250">
{{ user }}
</slot>
</span>
`,
data: function() {
return {
user: '姓名'
};
}
})
const app = new Vue({
el: '#app',
});
</script>
3. 数据
computed 计算属性
计算属性的结果会被缓存,依赖的data变化才会重新计算。
<div id="app">
<p>num {{num}}</p>
<p>num {{num}}</p>
<p>double1 {{double1}}</p>
<p>double1 {{double1}}</p>
<input v-model="double2"/>
</div>
var app = new Vue({
el: '#app',
data:{
num: 20
},
computed: {
double1() {
console.log('double1')
return this.num * 2
},
double2: {
get() {
console.log('double2get')
return this.num * 2
},
set(val) {
console.log('double2set')
this.num = val/2
}
}
}
})
watch 监听属性
监听数据的变化。
<div id="app">
<input v-model="name"/>
<input v-model="info.city"/>
</div>
var app = new Vue({
el: '#app',
data() {
return {
name: '双越',
info: {
city: '北京'
}
}
},
watch: {
name(oldVal, val) {
// eslint-disable-next-line
console.log('watch name', oldVal, val) // 值类型,可正常拿到 oldVal 和 val
},
info: {
handler(oldVal, val) {
// eslint-disable-next-line
console.log('watch info', oldVal, val) // 引用类型,拿不到 oldVal 。因为指针相同,此时已经指向了新的 val
},
deep: true // 深度监听
}
}
})
4. 生命周期
常用
- beforeCreate::在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。(服务器端渲染期间被调用)
- created:可以访问到data,(服务器端渲染期间被调用)
- beforeMount : 在挂载开始之前被调用:相关的渲染函数首次被调用
- mounted : el 被新创建的 vm.$el 替换, 挂载成功
一般在此时调用ajax,js是单线程的,dom加载完才会进行异步操作
// mounted 不保证子组件都被挂载。如果等到视图渲染完毕,可以在 mounted 内部使用 vm.$nextTick:
mounted: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been rendered
})
}
- beforeUpdate : 数据更新时调用
- updated :组件 DOM 已经更新完毕
// updated 不保证子组件都被重绘。如果等到视图重绘完毕,可以在 updated 里使用 vm.$nextTick:
updated: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been re-rendered
})
}
- beforeDestory():组件销毁前。
一般在此时解绑自定义事件和清除定时器。
- destoryed():组件销毁之后
不常用
- activated:当组件激活的时候调用
- deactivated:当组件停用的时候调用
- errorCaptured:当捕获一个来自子孙组件的错误时被调用。(服务器端渲染期间被调用)
拓展:父子组件的生命周期
- 加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
- 子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
- 父组件更新过程
父beforeUpdate->父updated
- 销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
5. 组件间的通讯
常见的有三种方式:父子间传值、非父子间自定义事件传值、vuex。
- 父传子 用 props
<div id="app">
<div>{{pmsg}}</div>
<menu-item :title='ptitle' :content='ptitle'></menu-item>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">
//父组件向子组件传值-基本使用
Vue.component('menu-item', {
props: ['title', 'content'],
data: function() {
return {
msg: '子组件本身的数据'
}
},
template: `
<div>
<p>{{msg}}</p>
<p>{{title}}</p>
<p>{{content}}</p>
</div>`
});
var vm = new Vue({
el: '#app',
data: {
pmsg: '父组件中内容',
ptitle: '动态绑定属性'
}
});
</script>
- 子传父 用 $emit
子组件写法
this.$emit(‘fa’, this.num)
父组件写法
<button-add @fa=“getNum”>
<div id="app">
<div>{{sonNum}}</div>
<!-- vue定义好的组件,可以重复使用·-->
<button-add @fa="getNum"></button-add>
</div>
<!--引入vue-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// 注册全局对象,要写在vue实例的上面
Vue.component('button-add', {
data: function () {
return {
num: 0
}
},
template: `<button @click="add">{{num}}</button>`,
methods: {
add: function () {
this.num = this.num + 1
this.$emit('fa', this.num)
}
}
})
// 创建vue实例
var vm = new Vue({
el: '#app',
data: {
sonNum: 0
},
methods: {
getNum: function (son) {
this.sonNum = son
}
}
})
</script>
- 非父子组件(兄弟组件),需要创建新的vue实例来自定义事件
用法
- 创建一个新的vue对象
var newvue = new Vue()
- 触发事件
newvue.$emit('自定义事件名', 参数)
- 监听事件
newvue.on('自定义事件名', 触发方法名)
- 销毁事件:需要自行销毁
newvue.off('自定义事件名')
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
<div>父组件</div>
<div>
<button @click='handle'>销毁事件</button>
</div>
<test-tom></test-tom>
<test-jerry></test-jerry>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
/*
兄弟组件之间数据传递
*/
// 提供事件中心
var hub = new Vue();
Vue.component('test-tom', {
data: function(){
return {
num: 0
}
},
template: `
<div>
<div>TOM:{{num}}</div>
<div>
<button @click='handle'>点击</button>
</div>
</div>
`,
methods: {
handle: function(){
hub.$emit('jerry-event', 2);
}
},
mounted: function() {
// 监听事件
hub.$on('tom-event', (val) => {
this.num += val;
});
}
});
Vue.component('test-jerry', {
data: function(){
return {
num: 0
}
},
template: `
<div>
<div>JERRY:{{num}}</div>
<div>
<button @click='handle'>点击</button>
</div>
</div>
`,
methods: {
handle: function(){
// 触发兄弟组件的事件
hub.$emit('tom-event', 1);
}
},
mounted: function() {
// 监听事件
hub.$on('jerry-event', (val) => {
this.num += val;
});
}
});
var vm = new Vue({
el: '#app',
data: {
},
methods: {
handle: function(){
hub.$off('tom-event');
hub.$off('jerry-event');
}
}
});
</script>
</body>
</html>
本文地址:https://blog.csdn.net/weixin_43745003/article/details/107279151