vue项目实战:实战技巧总结(上):https://developer.aliyun.com/article/1483347
十一、引入接口文件暴露到全局
11.1 在 main.js 里面引入接口暴露到全局'
// 接口暴露在全局 import { server } from './config/api' Vue.prototype.\$server = server;
//api.js export const server = { getContentMenu: (paramObj)=>fetch('/content/menu',paramObj),//内容详情查询 getContentListPort: (paramObj)=>fetch('/content/list/'+paramObj),//入口页面接口 getContentList:(paramObj)=>fetch('/content/list/'+paramObj),//内容详情查询 getPageviews:(paramObj)=>fetch('/webpage/1/view',paramObj)//流量统计接口 } 组件里面使用: ```js methods: { getPageviews() { var that = this; let params = { pageId: that.pageId, pageUrl: that.pageUrl, }; that.\$server.getPageviews(params).then(response => {}) } }
11.2 axios 方法封装,整个 api.js
import axios from 'axios'; axios.defaults.timeout = 5000; axios.defaults.baseURL =''; //填写域名 //http request 拦截器 axios.interceptors.request.use( config => { config.data = JSON.stringify(config.data); config.headers = { 'Content-Type':'application/x-www-form-urlencoded' } return config; }, error => { return Promise.reject(err); } ); //响应拦截器即异常处理 axios.interceptors.response.use(response => { return response }, err => { if (err && err.response) { switch (err.response.status) { case 400: console.log('错误请求') break; case 401: console.log('未授权,请重新登录') break; case 403: console.log('拒绝访问') break; case 404: console.log('请求错误,未找到该资源') break; case 405: console.log('请求方法未允许') break; case 408: console.log('请求超时') break; case 500: console.log('服务器端出错') break; case 501: console.log('网络未实现') break; case 502: console.log('网络错误') break; case 503: console.log('服务不可用') break; case 504: console.log('网络超时') break; case 505: console.log('http版本不支持该请求') break; default: console.log(`连接错误${err.response.status}`) } } else { console.log('连接到服务器失败') } return Promise.resolve(err.response) }) /** * 封装get方法 * @param url * @param data * @returns {Promise} */ export function fetch(url,params={}){ return new Promise((resolve,reject) => { axios.get(url,{ params:params }) .then(response => { resolve(response.data); }) .catch(err => { reject(err) }) }) } /** * 封装post请求 * @param url * @param data * @returns {Promise} */ export function post(url,data = {}){ return new Promise((resolve,reject) => { axios.post(url,data) .then(response => { resolve(response.data); },err => { reject(err) }) }) } /** * 官网接口请求封装 * @param url * @param data * @returns {Promise} */ export const server = { getContentMenu: (paramObj)=>fetch('/content/menu',paramObj),//内容详情查询 getContentListPort: (paramObj)=>fetch('/content/list/'+paramObj),//入口页面接口 getContentList:(paramObj)=>fetch('/content/list/'+paramObj),//内容详情查询 getPageviews:(paramObj)=>fetch('/webpage/1/view',paramObj)//流量统计接口 }
十二、provide /inject 完美解决不跳转不闪动页面刷新
原理:此方法使用的是 v-if 来控制 router-view 的显示或隐藏,v-if 从 false 变为 true 时,vue 会重新渲染 router-view 区域,所以当参数变化时,只需让 v-if 从 true => false => true,就能实现页面刷新。
12.1 找到route-view
//App.vue <template> <div id="app"> <router-view v-if="isRouterAlive"/> </div> </template> <script> export default { name: 'App', provide() { return { reload: this.reload//调用reload方法 } }, data() { return { isRouterAlive: true//一开始router-view为true } }, methods: { reload() { this.isRouterAlive = false //在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM this.$nextTick(() => { this.isRouterAlive = true }) } } } </script>
12.2在页面操作
export default { name: 'newproduct', inject:['reload'],//在export default下面加上这一段 method:{ //调用App.vue下的this.reload()方法,来改变v-if的状态 clickDiv(){//刷新按钮调用的方法 this.reload() } }
参考文档:如何实现 vue 中不跳转不闪动页面刷新?provide /inject 完美解决方案
十三、vue动态绑定 class
13.1 对象方法
:class="{ 'active': isActive }"
13.2 判断是否绑定一个active
:class="{'active':isActive==-1}" 或者 :class="{'active':isActive==index}"
13.3绑定并判断多个
第一种(用逗号隔开)
:class="{ 'active': isActive, 'sort': isSort }"
第二种(放在 data 里面)
:class="classObject" data() { return { classObject: { active: true, sort: false } } }
第三种(使用 computed 属性)
:class="classObject" data() { return { isActive: true, isSort: false } }, computed: { classObject: function() { return { active: this.isActive, sort: this.isSort } } }
13.4数组方法
1.单纯数组
:class="[isActive,isSort]"
data() { return { isActive: 'active', isSort: 'sort' } }
数组与三元运算符结合判断选择需要的class
三元运算符后面的“:”两边的class需要加上单引号
:class="[isActive?'active':'']"
或者
:class="[isActive==1?'active':'']"
或者
:class="[isActive==index?'active':'']"
或者
:class="[isActive==index?'active':'otherActiveClass']"
13.5 数组对象结合动态判断
//前面这个 active 在对象里面可以不加单引号,后面这个 sort 要加单引号
:class="[{ active: isActive }, 'sort']"
或者
:class="[{ active: isActive==1 }, 'sort']"
或者
:class="[{ active: isActive==index }, 'sort']"
应用于组件
如果直接在自定义组件中使用 class 或 :class,那么样式规则就会直接应在这个组件的根元素上。
<div id="app"> <text-component :class="{'isStrong':isStrong}"></text-component> </div>
<script> Vue.component('text-component', { template: '<p class="content">不懂基因测序的学霸不是好的人工智能公司 CEO</p>' }); var app = new Vue({ el: '#app', data: { isStrong: true } }); </script>
style三元表达式
<span v-bind:style="{'display':config.isHaveSearch ? 'block':'none'}" >动态绑定样式</span>
也可以使用 v-bind:style 或 :style 直接给 HTML 元素绑定样式,它也有对应的对象语法与数组语法。
<div id="app"> <div :style="border"></div> </div>
<script> var app = new Vue({ el: '#app', data: { border:{ border:'1px solid #00F', textShadow:'0 0 .3em gray' } } }); </script>
因为 JS 属性不支持短横分隔命名,所以我们这里使用 CSS 也支持的驼峰命名法。
计算属性computed
例:反转字符串:
<div id="app"> <p>原始字符串: {{ message }}</p> <p>计算后反转字符串: {{ reversedMessage }}</p> </div>
<script> var vm = new Vue({ el: '#app', data: { message: 'Runoob!' }, computed: { // 计算属性的 getter reversedMessage: function () { // `this` 指向 vm 实例 return this.message.split('').reverse().join('') } } }) </script>
我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。。换句话说,computed 是局部渲染,而 methods 是全部渲染
区别:
- 1.methods是个方法,比如你点击事件要执行一个方法,这时候就用methods,
- 2.computed是计算属性,实时响应的,比如你要根据data里一个值随时变化做出一些处理,就用computed。
- 3.我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
- 4.methods必须需要一定的条件去触发,而computed则不需要.
- 5.computed依赖缓存,如果不需要经常变动的用computed,需要经常变动的用methods。如果你需要传参数,就用methods。
computed
computed 属性默认只有 getter ,不过在需要时你也可以提供一个 setter :
var vm = new Vue({ el: '#app', data: { name: 'Google', url: 'http://www.google.com' }, computed: { site: { // getter get: function() { return this.name + ' ' + this.url }, // setter set: function(newValue) { var names = newValue.split(' ') this.name = names[0] this.url = names[names.length - 1] } } } })
// 调用 setter, vm.name 和 vm.url 也会被对应更新 vm.site = 'http://www.runoob.com'; document.write('name: ' + vm.name); document.write('<br>'); document.write('url: ' + vm.url);
从实例运行结果看在运行 vm.site = 'http://www.runoob.com'; 时,setter 会被调用, vm.name 和 vm.url 也会被对应更新。
十四、style样式绑定
class 与 style 是 HTML 元素的属性,用于设置元素的样式,我们可以用 v-bind 来设置样式属性。
Vue.js v-bind 在处理 class 和 style 时, 专门增强了它。表达式的结果类型除了字符串之外,还可以是对象或数组。
14.1 class 属性绑定
我们可以为 v-bind:class 设置一个对象,从而动态的切换 class:
<style> .active { width: 100px; height: 100px; background: green; } </style>
<div id="app"> <div v-bind:class="{ active: isActive }"></div> </div>
<script> new Vue({ el: '#app', data: { isActive: true } }) </script>
例:text-danger 类背景颜色覆盖了 active 类的背景色:
方法一:在对象中传入更多属性用来动态切换多个 class 。
<style> .active { width: 100px; height: 100px; background: green; } .text-danger { background: red; } </style>
<div id="app"> <div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"> </div> </div>
<script> new Vue({ el: '#app', data: { isActive: true, hasError: true } }) </script>
方法二:直接绑定数据里的一个对象:
<style> .active { width: 100px; height: 100px; background: green; } .text-danger { background: red; } </style>
<div id="app"> <div v-bind:class="classObject"></div> </div>
<script> new Vue({ el: '#app', data: { classObject: { active: true, 'text-danger': true } } }) </script>
方法三:绑定返回对象的计算属性:
<style> .active { width: 100px; height: 100px; background: green; } .text-danger { background: red; } </style>
<div id="app"> <div v-bind:class="classObject"></div> </div>
<script> new Vue({ el: '#app', data: { isActive: true, error: null }, computed: { classObject: function () { return { active: this.isActive && !this.error, 'text-danger': this.error && this.error.type === 'fatal', } } } }) </script>
方法四:数组语法
<style> .active { width: 100px; height: 100px; background: green; } .text-danger { background: red; } </style>
<div id="app"> <div v-bind:class="[activeClass, errorClass]"></div> </div>
<script> new Vue({ el: '#app', data: { activeClass: 'active', errorClass: 'text-danger' } }) </script>
还可以使用三元表达式来切换列表中的 class :
errorClass 是始终存在的,isActive 为 true 时添加 activeClass 类:
<style> .text-danger { width: 100px; height: 100px; background: red; } .active { width: 100px; height: 100px; background: green; } </style>
<div id="app"> <div v-bind:class="[errorClass ,isActive ? activeClass : '']"></div> </div>
<script> new Vue({ el: '#app', data: { isActive: true, activeClass: 'active', errorClass: 'text-danger' } }) </script>
style样式邦定
v-bind:style直接设置样式:
<div id="app"> <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">菜鸟教程</div> </div>
<script> new Vue({ el: '#app', data: { activeColor: 'green', fontSize: 30 } }) </script>
也可以直接绑定到一个样式对象:
<div id="app"> <div v-bind:style="styleObject">菜鸟教程</div> </div>
<script> new Vue({ el: '#app', data: { styleObject: { color: 'green', fontSize: '30px' } } }) </script>
v-bind:style 可以使用数组将多个样式对象应用到一个元素上:
<div id="app"> <div v-bind:style="[baseStyles, overridingStyles]">菜鸟教程</div> </div>
<script> new Vue({ el: '#app', data: { baseStyles: { color: 'green', fontSize: '30px' }, overridingStyles: { 'font-weight': 'bold' } } }) </script>
十五、vue组件参数传递:
Vue 组件间通信包括:父子组件间通信,兄弟组件间通信以及模块之间通信等。Vue 是数据驱动视图更新的框架, 所以对于 Vue 来说组件间的数据通信非常重要。Vue 实现组件间通信有很多方式,今天我来给大家讲解一下父子组件间通信:props 和$emit。
15.1.子组件向父组件传递参数;
子组件 A:
<template> <div class="childA-wrapper"> 子组件A </div> </template> <script> export default { data() { return { childA: '我是组件A传过来的值' } }, created: function() {}, mounted() { this.sendDataParent() }, methods: { sendDataParent() { // getChildDataA是在父组件on监听的方法 // 第二个参数this.childA是需要传的值 this.$emit('getChildDataA', this.childA) } } } </script>
子组件 B:
<template> <div class="childB-wrapper"> 子组件B </div> </template> <script> export default { data() { return { childB:'我是组件B传过来的值' } }, created:function() { }, mounted(){ this.sendDataParent() }, methods: { sendDataParent() { // getChildDataB是在父组件on监听的方法 // 第二个参数this.childB是需要传的值 this.$emit('getChildDataB', this.childB) } } } </script>
父组件:
<template> <div> <v-childA v-on:getChildDataA="getChildDataA"></v-childA> <v-childB v-on:getChildDataB="getChildDataB"></v-childB> <div>获取组件A传过来的值:{{childAValue}}</div> <div>获取组件B传过来的值:{{childBValue}}</div> </div> </template> <script> import childA from '@/components/childA.vue' import childB from '@/components/childB.vue' export default { data() { return { childAValue:'', childBValue:'', } }, methods: { getChildDataA(childA){ console.log(childA) this.childAValue=childA }, getChildDataB(childB){ console.log(childB) this.childBValue=childB } }, components: { 'v-childA': childA, 'v-childB': childB} } </script>
vue项目实战:实战技巧总结(下):https://developer.aliyun.com/article/1483360