【Vue.js】Vue.js基本语法
作者:神秘网友
发布时间:2020-09-22 06:32:31
【Vue.js】Vue.js基本语法
【Vue.js】Vue.js基本语法双大括号表达式
- 语法:
{{exp}}
- 功能:(1)向页面输出数据;(2)内部可以是变量、对象调用、表达式
强制数据绑定
- 语法:
v-bind:aaa='bbb'
,bbb会作为表达式解析执行;简洁写法::aaa='bbb'
- 功能:(1)向页面输出数据;(2)内部可以是变量、对象调用、表达式
绑定事件监听
- 语法:
v-on:click='aaa'
,aaa是指绑定指定事件名的回调函数;简洁写法:@click='aaa'
- 功能:触发一个事件
示例代码
## Template.vue <template> <div> <h3>双括号表达式</h3> <div>{{intro}}</div> <div>{{intro.toUpperCase()}}</div> <h3>强制数据绑定</h3> <a href="site">撩课学院</a><br> <a v-bind:href="site">撩课学院</a><br> <a :href="site">撩课学院</a><br> <h3>绑定事件监听</h3> <p><button v-on:click="study">学习Vue</button></p> <p><button @click="study">学习Vue</button></p> <p><button @click="study('小撩')">学习Vue</button></p> </div> </template> <script> export default { name: "Template", data(){ return { intro: 'like it, it like!', site: 'http://www.itLike.com' } }, methods: { study(name){ alert(`${name},祝你学有所成!`); } } } </script> <style scoped> </style>
## App.vue <template> <div id="app"> <Template /> </div> </template> <script> // 1. 引入 import Template from './components/Template.vue' export default { name: 'app', // 注册组件 components: { Template } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
计算属性(computed)
- 作用:
- 减少模板中的计算逻辑
- 进行数据缓存
- 依赖固定的数据类型(响应式数据)
- 使用:
- 在computed属性对象中定义计算属性的方法
- 在页面中使用{{方法名}}来显示计算的结果
- 通过getter/setter实现对属性数据的显示和监视
侦听器(watch)
- 作用:
- 比computed更加灵活
- watch中可以执行任何逻辑,比如:函数节流、Ajax异步数据获取、甚至操作DOM
- 依赖固定的数据类型(响应式数据)
- 使用:
- 通过通过vm对象的$watch()或watch配置来监视指定的属性
- 当属性变化时, 回调函数自动调用, 在函数内部进行计算
总结
- computed能做的,watch都能做,反之则不行
- 能用computed的地方,尽可能使用computed
- computed 是计算一个新的属性,并将该属性挂载到 vm(Vue 实例)上,而 watch 是监听已经存在且已挂载到 vm 上的数据,所以用 watch 同样可以监听 computed 计算属性的变化(其它还有 data、props)
- computed 本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,第一次访问 computed 属性,才会计算新的值,而 watch 则是当数据发生变化便会调用执行函数
- 从使用场景上说,computed 适用一个数据被多个数据影响,而 watch 适用一个数据影响多个数据
示例代码
## ComputedAndWatch.vue <template> <div> <label>姓:<input type="text" placeholder="请输入姓氏" v-model="firstName"></label> <p></p> <label>名:<input type="text" placeholder="请输入名字" v-model="lastName"></label> <p>-----------------------------------------------------------------------</p> <!--单向--> <label>姓 名:<input type="text" placeholder="请输入姓名" v-model="fullNameOne"></label> <p></p> <!--双向--> <label>姓 名:<input type="text" placeholder="请输入姓名" v-model="fullNameTwo"></label> <p></p> <!--双向--> <label>姓 名:<input type="text" placeholder="请输入姓名" v-model="fullNameThree"></label> </div> </template> <script> export default { name: "ComputedAndWatch", data(){ return { firstName: '', // 姓 lastName: '', // 名 fullNameThree: '' // 被watch监听改变 } }, // 配置计算属性 computed: { // 计算属性 姓名 fullNameOne: { get(){ return this.firstName + '·' + this.lastName } }, fullNameTwo: { get(){ // console.log(`调用了fullNameTwo的getter方法`); return this.firstName + '·' + this.lastName; }, set(value){ // console.log(`调用了fullNameTwo的setter方法, 值:${value}`); // 1.更新firstName和lastName let names = value.split('·'); console.log(names); this.firstName = names[0]; this.lastName = names[1]; } } }, // 配置watch watch: { // 监听firstName firstName(value){ console.log(`watch监视到firstName发生改变:${value}`); // 更新fullNameThree this.fullNameThree = value + '·' + this.lastName; }, // 监听lastName lastName(value){ console.log(`watch监视到lastName发生改变:${value}`); // 更新fullNameThree this.fullNameThree = this.firstName + '·' + value; } } } </script> <style scoped> </style>
## App.vue <template> <div id="app"> <!--<computed-and-watch />--> <ComputedAndWatch /> </div> </template> <script> // 1. 引入 import ComputedAndWatch from './components/ComputedAndWatch.vue' export default { name: 'app', // 注册组件 components: { ComputedAndWatch } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
概念
- 在模板界面中,某些元素的样式是变化的,class/style用于动态绑定类和样式
- class/style绑定技术就是专门用来处理动态样式效果
class
:class='aaa'
- aaa取值:字符串、对象、数组
style
:style="{ backgroundColor: bgColor, fontSize: fSize}"
- 其中 bgColor/fSize 都是 data 属性
示例代码
## ClassAndStyle.vue <template> <div> <h3>class的使用</h3> <div :class="oneClass">样式类可以是字符串</div> <div :class="{classOne: true, classTwo: true}">样式类可以是对象</div> <div :class="['classOne', 'classTwo']">样式类可以是数组</div> <div :class="[oneClass, twoClass]">样式类可以是数组</div> <p>------------------------------------------------------------</p> <h3>style的使用</h3> <div style="width: 300px; height: 200px; margin: 10px auto;" :style="{backgroundColor: bgColor, fontSize: fSize}">样式类可以是字符串</div> </div> </template> <script> export default { name: "ClassAndStyle", data() { return { oneClass: 'classOne', twoClass: 'classTwo', bgColor: 'red', fSize: '30px' } } } </script> <style scoped> .classOne { font-size: 30px; color: red; } .classTwo { width: 400px; height: 200px; background-color: deepskyblue; margin: 10px auto; } </style>
## App.vue <template> <div id="app"> <ClassAndStyle /> </div> </template> <script> import ClassAndStyle from './components/ClassAndStyle' export default { name: 'app', components: { ClassAndStyle } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
v-if/v-else/v-else-if
v-show
两者区别
- v-if是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建
- v-show不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换
- 如果需要频繁切换 v-show 较好
示例代码
## IfAndShow.vue <template> <div> <div v-if="flag">今晚要上课!</div> <div v-else>今晚不上课!</div> <p></p> <p>--------------------------------------------------------</p> <div v-show="flag">今晚讲Vue!</div> <div v-show="!flag">今晚不讲Vue!</div> <p></p> <button @click="flag = !flag">切换</button> </div> </template> <script> export default { name: "IfAndSHow", data(){ return { flag: true, // 上课 不上课 } } } </script> <style scoped> </style>
## App.vue <template> <div id="app"> <IfAndShow /> </div> </template> <script> import IfAndShow from './components/IfAndShow' export default { name: 'app', components: { IfAndShow } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
为什么要绑定Key?
- key是给每一个vnode的唯一id,可以依靠key,更准确、更快地拿到oldVnode中对应的vnode节点
- 尽可能不要使用index作为key,会带来状态bug问题
- 最好使用静态key作为Dom的key,比如第三方库shortid
数组遍历
对象遍历
过滤遍历
排序遍历
示例代码
## ListRender.vue <template> <div> <h3>遍历数组</h3> <ul> <li v-for="(person, index) in persons" :key="personsKeys[index]"> ID: {{personsKeys[index]}} ---- {{index}} ) 姓名:{{person.name}}, 年龄:{{person.age}}, 性别:{{person.sex}} </li> </ul> <h3>遍历对象</h3> <ul> <li v-for="(item, key) in persons[0]"> {{key}} --- {{item}} </li> </ul> </div> </template> <script> import shortId from 'shortid' export default { name: "ListRender", data(){ return { persons: [ {name: '张三', age: 18, sex: '男'}, {name: '李四', age: 28, sex: '女'}, {name: '王五', age: 38, sex: '男'}, {name: '赵六', age: 48, sex: '女'}, {name: '李奇', age: 58, sex: '男'} ], personsKeys: [] } }, mounted() { this.personsKeys = this.persons.map(v=>shortId.generate()) } } </script> <style scoped> ul{ list-style: none; } </style>
## App.vue <template> <div id="app"> <ListRender /> </div> </template> <script> import ListRender from './components/ListRender' export default { name: 'app', components: { ListRender } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
## ListRenderTwo.vue <template> <div> <div> <h3>排序</h3> <button @click="orderByAge(0)">默认</button> <button @click="orderByAge(2)">年龄↑</button> <button @click="orderByAge(1)">年龄↓</button> </div> <p>-------------------------------------------------------------------</p> <h3>搜索列表</h3> <input type="text" placeholder="请输入要搜索的姓名" v-model="searchName"> <ul> <li v-for="(p, index) in filterPersons" :key="personsKeys[index]"> {{index + 1}}) 姓名:{{p.name}} --- 性别:{{p.sex}}--- 年龄:{{p.age}}--- 电话:{{p.phone}} </li> </ul> </div> </template> <script> import shortId from 'shortid' export default { name: "ListRenderTwo", data() { return { searchName: '', persons: [ {name: '张三', sex: '女', age: 19, phone: '18921212121'}, {name: '李四', sex: '男', age: 29, phone: '18921221121'}, {name: '王五', sex: '女', age: 39, phone: '18921788721'}, {name: '赵六', sex: '男', age: 49, phone: '18921556121'}, {name: '李四', sex: '男', age: 29, phone: '18921221121'}, {name: '王五', sex: '女', age: 39, phone: '18921788721'}, {name: '李四', sex: '男', age: 29, phone: '18921221121'}, {name: '王五', sex: '女', age: 39, phone: '18921788721'}, {name: '王五', sex: '女', age: 39, phone: '18921788721'}, {name: '赵六', sex: '男', age: 49, phone: '18921556121'}, {name: '李思思', sex: '男', age: 29, phone: '18921221121'}, {name: '张三', sex: '女', age: 19, phone: '18921212121'}, {name: '李四', sex: '男', age: 29, phone: '18921221121'}, {name: '王五', sex: '女', age: 39, phone: '18921788721'}, {name: '赵六', sex: '男', age: 49, phone: '18921556121'}, {name: '李四', sex: '男', age: 29, phone: '18921221121'}, {name: '王五', sex: '女', age: 39, phone: '18921788721'}, {name: '李四', sex: '男', age: 29, phone: '18921221121'}, {name: '王五', sex: '女', age: 39, phone: '18921788721'}, {name: '王五', sex: '女', age: 39, phone: '18921788721'}, {name: '赵六', sex: '男', age: 49, phone: '18921556121'}, {name: '李五五', sex: '男', age: 29, phone: '18921221121'} ], personsKeys: [], orderType: 0 // 排序 } }, computed: { filterPersons() { // 1. 获取数据 let {searchName, persons, orderType} = this; // 2. 取出数组中的数据 let arr = [...persons]; // 3. 过滤数组 if (searchName.trim()) { arr = persons.filter(p => p.name.indexOf(searchName) !== -1); } // 4. 排序 if (orderType) { arr.sort((p1, p2) => { if (orderType === 1) { // 降序 return p2.age - p1.age } else { // 升序 return p1.age - p2.age } }); } return arr; } }, mounted() { this.personsKeys = this.filterPersons.map(v => shortId.generate()) }, methods: { orderByAge(orderType) { this.orderType = orderType; } } } </script> <style scoped> ul { list-style: none; } ul li { padding: 4px 0; } </style>
## App.vue <template> <div id="app"> <ListRenderTwo /> </div> </template> <script> import ListRenderTwo from './components/ListRenderTwo' export default { name: 'app', components: { ListRenderTwo } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
自定义指令
- 自定义全局组件
/* 注册全局组件 el: 指令所在的标签对象 binding: 包含指令相关数据的容器对象 */ Vue.directive('upper-text', (el, binding)=>{ console.log(el, binding.value); el.textContent = binding.value.toUpperCase() });
- 自定义局部组件
// 自定义局部组件 directives: { 'lower-text'(el, binding) { console.log(el, binding); el.textContent = binding.value.toLowerCase() } }
示例代码
## main.js import Vue from 'vue' import App from './App.vue' Vue.config.productionTip = false; /* 注册全局指令 */ Vue.directive('upper-word', (el, binding)=>{ console.log(el, binding); el.textContent = binding.value.toUpperCase(); }); new Vue({ render: h => h(App), }).$mount('#app');
## OtherInstruct.vue <template> <div> <!--v-text和v-html--> <p>{{content}}(Like IT, IT Like)</p> <p v-text="content">(Like IT, IT Like)</p> <p v-html="content"></p> <!--v-pre--> <p v-pre>{{intro}}</p> <p v-cloak>{{message}}</p> <!--v-once--> <p v-once>{{name}}</p> <p>{{name}}</p> <input type="text" placeholder="请输入姓名" v-model="name"> <!--ref--> <p ref="fish">我是一只鱼</p> <button @click="log">输出内容</button> <!--使用自定义指令--> <p v-upper-word="word1"></p> <p v-lower-word="word2"></p> </div> </template> <script> export default { name: "OtherInstruct", data(){ return { content: '<a href="http://www.itlike.com">撩课学院</a>', intro: 'Like It', message: '还有半个小时就10:30', name: '小撩', word1: 'it like, like it', word2: 'IT LIKE, LIKE IT' } }, methods:{ log(){ // console.log(this.$refs.fish); console.log(this.$refs.fish.innerHTML); } }, // 自定义局部指令 directives: { 'lower-word'(el, binding){ console.log(el, binding); el.textContent = binding.value.toLowerCase(); } } } </script> <style scoped> [v-cloak]{ display: none; } </style>
<template> <div id="app"> <OtherInstruct /> </div> </template> <script> import OtherInstruct from './components/OtherInstruct' export default { name: 'app', components: { OtherInstruct } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>