vue相关的知识

1. 组件的data为什么必须是函数?

组件中的 data 写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的 data ,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个组件的值发生改变,全部组件都会变的结果。

这样的好处就是每各个组件可以维护各自的数据,如果 data 是一个对象则会影响到其他组件。
2. 问 v-if 和 v-show 有什么区别?

相同点:v-if与v-show都可以动态控制dom元素显示隐藏

不同点:v-if隐藏是将dom元素整个删除,而v-show隐藏则是为该元素添加css--display:none,dom元素还在。

3. vue几种常用的指令

v-text:元素的innerText属性(不带标签)
v-html:元素的innerHTML属性(带标签)
v-bind:绑定属性
v-on:绑定事件,绑定的事件从methods中获取

事件修饰符
.stop:阻止冒泡,调用 event.stopPropagation()
.prevent:阻止默认事件,调用 event.preventDefault()
.capture:添加事件侦听器时使用事件捕获模式

v-model
作用:在表单元素上创建双向数据绑定
说明:监听用户的输入事件以更新数据

所谓的双向绑定,就是你在view视图层里面改变了值,vue里面对应的值也会改变。只能给具备value属性的元素进行双向数据绑定。

v-if 和 v-show
条件渲染
v-if:根据表达式的值的真假条件,销毁或重建DOM元素
v-show:根据表达式之真假值,切换元素的 display: block/none 属性

v-for
作用:基于源数据多次渲染元素或模板块,使用 v-for 的时候提供 key 属性,可以提高列表渲染的效率,提高页面的性能。

v-once 提升性能
说明:只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。

4. 对于Vue是一套渐进式框架的理解

Vue.js是一个渐进式框架,只需要具备基本的HTML/CSS/JavaScript基础就可以快速上手。在用Vue.js构建大型应用时推荐使用NPM安装,但是需要注意npm的版本需要大于3.0。

在通过npm安装项目后,我们需要对其目录进行解析:
(1) build:项目构建(webpack)相关代码;
(2) config:配置目录,包括端口号等。
(3) node_modules:npm加载的项目依赖模块
(4) src:这个目录当中的内容包含了我们基本上要做的事情,这里包含了几个文件:
(一)assets:存放图片
(二)components:存放组件文件
(三)App.vue:项目入口文件,组件也可以直接写在这里不适用components
(四)main.js:核心文件
(5) static:静态资源目录
(6) test:初始测试目录
(7) .xxxx:配置文件,包括git配置和语法配置等
(8) index.html:首页
(9) package.json:项目配置文件
(10) README.md:说明文档

Vue的mvvm框架给了前端一种思路:完全基于数据驱动,帮助你从繁杂的dom操作中解脱出来

使用Vue的过程就是定义MVVM各个组成部分过程的过程:
(1) 定义View
(2) 定义Model
(3) 创建一个Vue实例或“ViewModel”

在创建Vue实例的时候,需要传入选项对象,可以包含挂载元素、数据等。

Vue实例被创建前会经过初始化,然后在数据变化时更新DOM,在这个期间也会调用一些生命周期钩子,从而我们可以自定义逻辑。总共可以分为8个段:

(1) beforeCreate 初始化实例后 数据观测和事件配置之前调用
(2) created 实例创建完成后调用
(3) beforeMount 挂载开始前被用
(4) mounted el被新建vm.$el替换并挂在到实例上之后调用
(5) beforeUpdate 数据更新时调用
(6) updated 数据更改导致的DOM重新渲染后调用
(7) beforeDestory 实例被销毁前调用
(8) destoryed 实例销毁后调用

需要注意的是created和mounted的区别,created是实例已经创建但未挂载,所以一些dom操作要放在mounted中。

Vue组件的API来自props(允许外部环境传递数据给组件)、events(允许组件触发外部环境副作用)和slots(允许外部环境将额外的内容组合在组件中)三个部分,组件的data属性必须是函数。

渐进的理解:vue只是个轻量视图而已,只做自己该做的事,不做不该做的事。

5. vue中使用 v-for 时,绑定key的作用

可以提高列表渲染的效率,提升页面的性能。

6. v-for 与 v-if 的优先级

当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级,这意味着 v-if 将分别重复运行于每个 v-for 循环中,所以,不推荐v-if和v-for同时使用。

7. axios 解决跨域问题

一、使用脚手架创建好项目
全局安装 vue-cli
npm install --global vue-cli
创建一个基于 webpack 模板的新项目
vue init webpack vue-demo
进入项目,安装依赖,启动项目
cd vue-demo
npm install
npm run dev
二、安装axios,并配置相应文件。这里跨域请求的接口来自豆瓣的api
安装 npm install axios --save
配置:
1、在 src/main.js 中引入使用
import axios from 'axios';
Vue.prototype.$axios=axios;
2、在 config/index.js 中的 的dev 添加以下代码,设置一下proxyTable;

proxyTable:{
    '/api': {
          target : 'https://movie.douban.com/',    //设置你调用的接口域名和端口号.别忘了加http
          changeOrigin : true,   //允许跨域
          pathRewrite : {
               '^/api': ''
               // '/'这里理解成用‘/api’代替target里面的地址,后面组件中我们掉接口时直接用api代替。比如我要调用'https://movie.douban.com/v2/movie/top250',直接写‘/api/v2/movie/top250’即可.
          }
    }
},

3、在 config/dev.env.js 中设置以下代码

module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',  //开发环境
  API_HOST: "/api/"
})

4、在 config/prod.env.js 中设置以下代码

module.exports = {
  NODE_ENV: '"production"',//生产环境
  API_HOST: '"https://movie.douban.com/"'
}

5、修改 src/components/HelloWorld.vue 文件

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <ul>
      <li v-for="item in movieArr">
        <span>{{item.title}}</span>
      </li>
    </ul>
    <button @click="sayOut">渲染</button>
  </div>
</template>

<script>
import axios from 'axios';
export default {
  name: 'HelloWorld',
  data() {
    return {
      msg: '调用豆瓣api',
      movieArr : []
    }
  },
  methods:{
    sayOut () {
      this.$axios.get('/').then((res) => {
        console.log(res)
        if (res.status == 200){
          console.log(res.data)
          // this.movieArr = res.data.subjects
        }
        // 这里要强调一下这个 this 箭头函数指的是它的父级也就是vue实例  然后不用箭头函数的话 this是一个undefined,无法给movieArr来赋值。
      })
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
</style>

到此 axios 跨域成功解决。

8. axios 封装http请求
  1. 在main.js 中引入
import axios from 'axios'
import {get, post, patch, put} from './config/http'
// 定义全局变量
Vue.prototype.$get=get;
Vue.prototype.$post=post;
Vue.prototype.$patch=patch;
Vue.prototype.$put=put;

2.src目录下创建config文件夹,config文件夹创建http.js

import axios from 'axios';

axios.defaults.timeout = 5000;
axios.defaults.baseURL ='';


//http request 拦截器
axios.interceptors.request.use(
  config => {
    // const token = getCookie('名称');注意使用的时候需要引入cookie方法,推荐js-cookie
    config.data = JSON.stringify(config.data);
    config.headers = {
      'Content-Type':'application/json;charset=UTF-8'         // 处理json
      // 'Content-Type':'application/x-www-form-urlencoded'   // 处理hash
    }
    // if(token){
    //   config.params = {'token':token}
    // }
    return config;
  },
  error => {
    return Promise.reject(err);
  }
);


//http response 拦截器
axios.interceptors.response.use(
  response => {
    if(response.data.errCode ==2){
      router.push({
        path:"/login",
        querry:{redirect:router.currentRoute.fullPath}//从哪个页面跳转
      })
    }
    return response;
  },
  error => {
    return Promise.reject(error)
  }
)


/**
 * 封装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)
          })
   })
 }

 /**
 * 封装patch请求
 * @param url
 * @param data
 * @returns {Promise}
 */

export function patch(url,data = {}){
  return new Promise((resolve,reject) => {
    axios.patch(url,data)
         .then(response => {
           resolve(response.data);
         },err => {
           reject(err)
         })
  })
}

 /**
 * 封装put请求
 * @param url
 * @param data
 * @returns {Promise}
 */

export function put(url,data = {}){
  return new Promise((resolve,reject) => {
    axios.put(url,data)
         .then(response => {
           resolve(response.data);
         },err => {
           reject(err)
         })
  })
}
  1. 在项目的 config/index.js 解决跨域请求
proxyTable: {
    '/apis': {
        // target: 'http://39.105.189.51:8052',
        target: 'http://api.edgvip.cn',
        changeOrigin: true,
        pathRewrite: {
          '^/apis': ''
        }
    }
},
  1. 组件中引入使用
    eg: 接口文档为下图


    image.png
methods: {
    login() {
      this.$post('apis/api/user/login1',{mobilePhone: this.mobilePhone, password: this.password}).then((res) => {
        // console.log(res)
        if(res.rs == 1){
          this.$toast(res.info);
          this.$router.push('/home');  // 路由跳转
        }else{
          this.$toast(res.info); 
        }
      })
    },
  },

此时,完成axios的封装。

9. vue 实现tab切换

其实就是路由的使用

  1. src下创建router文件夹,内部包含index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import News from '@/components/News'

Vue.use(Router)

export default new Router({
  routes: [
        {
            path: '/',
            component: Home
        },
        {
            path: '/home',
            name: 'Home',
            component: Home
        },
        {
            path: '/news',
            name: 'News',
            component: News
        }
    ]
})
  1. 在main.js 中引入router
import router from './router'

new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})
  1. 在App.vue中使用
<template>
  <div id="app">
    <img src="./assets/logo.png">
    <div>
      <router-link to="/home">主页</router-link>
      <router-link to="/news">新闻</router-link>
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style scoped>
</style>
10. 如何配置 vue 打包生成文件的路径?
  1. 将 config.js 文件下index.js中的assersPublishPath,改为‘./’
build: {
    // Template for index.html
    index: path.resolve(__dirname, '../dist/index.html'),

    // Paths
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
 // 将 build 中的 assetsPublicPath 改为 './', 修改dev,无效
    assetsPublicPath: './',

    /**
     * Source Maps
     */

    productionSourceMap: true,
    // https://webpack.js.org/configuration/devtool/#production
    devtool: '#source-map',

    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],

    // Run the build command with an extra argument to
    // View the bundle analyzer report after build finishes:
    // `npm run build --report`
    // Set to `true` or `false` to always turn it on or off
    bundleAnalyzerReport: process.env.npm_config_report
  }
  1. 将build/utils.js 加入 publicPath: '../../'
// Extract CSS when that option is specified
    // (which is the case during production build)
    if (options.extract) {
      return ExtractTextPlugin.extract({
        use: loaders,
        fallback: 'vue-style-loader',  
        // 在 utils.js 的此处加上下面代码,即可
        publicPath: '../../'
      })
    } else {
      return ['vue-style-loader'].concat(loaders)
    }
11. vue如何适配移动端?

在 main.js 引入 rem.js

import './config/rem'

rem.js 代码如下:

window.onload = function() {
    getRem(750, 100);
}

window.onresize = function() {
    getRem(750, 100);
}

function getRem(pwidth, prem) {
    var html = document.documentElement;
    var oWidth = document.body.clientWidth || document.documentElement.clientWidth;
    html.style.fontSize = oWidth/pwidth*prem + 'px';
}
12. vue如何优化首屏加载速度?
  1. 使用CDN资源,减小服务器带宽压力;
  2. 将静态js css放到其他地方(如OSS),减小服务器压力;
  3. 按需加载第三方UI资源;
  4. 服务端开启gzip,减小网络传输的流量大小;
  5. 按照页面或者组件分块懒加载
13. vue.js的两个核心思想

数据驱动 和 组件系统

14. vue数据的双向绑定

在vue.js里面只需要改变数据,Vue.js通过directives指令去操作DOM元素,当数据发生变化,会通知指令去修改对应的DOM,数据的变化驱动DOM的变化,DOM是数据的一种映射。vue.js还会对DOM做一些监听(DOM Listener),当我们修改视图的时候,vue.js监听到这些变化,从而改变数据。这样就形成了数据的双向绑定。

15. MVVM框架的理解

MVVM 由 Model、View、ViewModel 三部分构成,Model 代表数据层;View 代表视图层,它负责将数据模型转化成UI 展现出来;ViewModel 是一个同步View 和 Model的实例对象。

【model模型】指的是后端传递的数据。【view视图】指的是所看到的页面。【viewmodel视图模型】是mvvm模式的核心,它是连接view和model的桥梁。它有两个方向:一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定。

在MVVM模式下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。


image.png
15. 自定义指令和自定义过滤器

自定义指令

自定义指令的参数有:
el: 指令所绑定的元素,可以用来直接操作 DOM 。
binding: 一个对象,包含以下属性:
name: 指令名,不包括 v- 前缀。
value: 指令的绑定值, 例如: v-my-directive="1 + 1", value 的值是 2。
oldValue: 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
expression: 绑定值的字符串形式。 例如 v-my-directive="1 + 1" , expression 的值是 "1 + 1"。
arg: 传给指令的参数。例如 v-my-directive:foo, arg 的值是 "foo"。
modifiers: 一个包含修饰符的对象。 例如: v-my-directive.foo.bar, 修饰符对象 modifiers 的值是 { foo: true, bar: true }。

eg:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>自定义指令</title>
    <script src="https://cdn.bootcss.com/vue/2.6.6/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <div class="box" v-pos:red.left.top="true">自定义指令,背景色为红色,固定在左上角</div>
        <div class="box" v-pos.right.bottom="true">自定义指令,固定在右下角</div>
    </div>
</body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {

        },
        directives: {
            pos (el, binding){
                console.log(el, binding);
                // 修饰符 .left.top
                var position = binding.modifiers;
                // position = {left: true, top: true}
                // 绑定的参数 :red
                var color = binding.arg;
                if (binding.value){
                    el.style.position = 'fixed';
                    el.style.background = color;
                    for(let val in position){
                        el.style[val] = '10px'
                    } 
                }
            }
        }
    })
</script>
</html>

自定义过滤器

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>自定义指令</title>
    <script src="https://cdn.bootcss.com/vue/2.6.6/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <div><span>{{length}}m</span>=<span>{{length | meter("cm")}}</span></div>
        <div>{{price | myCurrency('$')}}</div>
    </div>
</body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            length: 1,
            price: 120
        },
        filters: {
            meter (val, unit){
                console.log(val, unit);
                return val*100 + unit
            },
            myCurrency(val, unit) {
                console.log(val, unit);
                return unit + val
            }
        }
    })
</script>
</html>
16. vue-cli 工程常用的 npm 命令有哪些?

下载 node_modules 资源包的命令:

npm install

// 安装模块;
// -save-dev(-D) 是指将包信息添加到 package.json 里的 devDependencies节点,表示开发时依赖的包。
npm install 模块名 --save-dev(-D)

// -save(-S) 是指将包信息添加到 package.json 里的dependencies节点,表示发布时依赖的包。
npm install 模块名 --save(-S)

启动 vue-cli 开发环境的 npm命令:

npm run dev 

vue-cli 生成 生产环境部署资源 的 npm命令:

npm run build 

用于查看 vue-cli 生产环境部署资源文件大小的 npm命令:

npm run build --report
17. vue常用的修饰符
<!-- 阻止单击事件继续传播(阻止冒泡)-->
<div onclick="alert(2)">
    <button class="btn" onclick="someEvents()">按钮</button>
</div>
<script>
    function someEvents(event) {
        alert(1);
        var event = event || window.event;
        event.stopPropagation();
    }
</script>
<a v-on:click.stop="doThis"></a>

<!-- 提交事件不再重载页面 (默认事件) -->
//  event.preventDefault();  //取消默认事件
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>

<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>

<!-- 在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 。-->
<input v-model.lazy="msg" >

<!-- 自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符 -->
<input v-model.number="num" >

<!-- 自动过滤用户输入的首尾空格 -->
<input v-model.trim="msg" />
18. vue事件中如何使用event对象?
<div>
    <button id="btn" @click="click">click me</button>
    <button @click="click()">click you</button>
    <button @click="click($event)">click us</button><br/>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        methods: {
            click() {
                // 获取当前 DOM 元素
                var el = event.currentTarget;
                // docuemnt.getElementById('btn') == event.currentTarget;
                console.log(el.innerHTML);
            }
        }
    })
</script>

// 三种写法
1.  DOM 事件 click 上,不加(),methods 方法中 click,可加可不加 event;
2.  DOM 事件 click 上,加(),methods 方法中 click,不能加 event;
3.  DOM 事件 click 上,加($event),并传入 $event,methods 方法中 click,可加可不加 event;
19. nextTick的使用
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>nextTick</title>
    <script src="https://cdn.bootcss.com/vue/2.6.6/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <p ref="txt" id="p1" v-if="show">{{message}}</p>
        <p>{{msg}}</p>
        <button @click="getTxt">点击</button>
    </div>
</body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            show: true,
            message: '原文本',
            msg: ''
        },
        methods: {
            getTxt () {
                this.show = true;
                // 箭头函数写法
                this.$nextTick(() => {
                    console.log(this.$refs.txt);                // <p id="p1">原文本</p>
                    console.log(document.getElementById('p1')); // <p id="p1">原文本</p>               
                    this.msg = this.$refs.txt.innerHTML +' + '+ '新文本内容';
                    console.log('原文本内容:', this.$refs.txt.innerHTML);
                })
                // this异步绑定 .bind(this)
                // this.$nextTick().then(function() {
                //  this.msg = this.$refs.txt.innerHTML +' + '+ '新文本内容';
                //      console.log('原始文本内容:', this.$refs.txt.innerHTML);
                // }.bind(this));
            }
        }
    })
</script>
</html>

解析:使用v-show进行显示隐藏,methods里面是直接可以获取到文本值,如果用v-if,是不能获取的文本值的。

this.$nextTick的作用是在下次dom更新循环完成之后进行调用
ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。

元素上绑定 ref (eg: ref='txt') 属性,获取该元素使用 this.$refs.txt 即可。也可使用事件(event)获取当前元素(var el = event.currentTarget)。

20. vue中 keep-alive 组件的作用
<!-- App.vue -->
<template>
  <div id="app">
      <router-link to="/home">主页</router-link>
      <router-link to="/news">新闻</router-link>
      
      <keep-alive include="keep_alive">
          <router-view v-if="$route.meta.keepAlive"></router-view>
      </keep-alive>
      <router-view v-if="!$route.meta.keepAlive"></router-view>
  </div>
</template>
<script>
export default {
  name: 'App',
  data() {
    return {
      include: "keep_alive"
    }
  }
}
</script>

<!-- 哪个组件需要缓存 该组件 name 就需要绑定App.vue的 include 属性,并在 routes 上绑定 meta: { keepAlive: true } -->
<!-- // true表示需要使用缓存  false表示不需要被缓存 -->
<!-- Home.vue -->
<template>
    <div id="home">
        <input type="text" placeholder="" name="">
    </div>
</template>
<script>
    export default {
        // 此时绑定的 name 是 App.vue 的 include 属性值
        name: 'keep_alive',
        data() {
            return {}
        }
    }
</script>


<!-- News.vue -->
<template>
    <div id="news">
        <input placeholder="输入框"></input>
    </div>
</template>
<script>
    export default {
        // 同 Home
        name: 'keep_alive',
        data() {
            return {}
        }
    }
</script>
<style scoped>
    
</style>

<!-- router/index.js -->
<script>
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import News from '@/components/News'
Vue.use(Router)
var routes = [
    {
        path: '/',
        component: Home
    },
    {
        path: '/home',
        name: 'Home',
        component: Home,
        meta: {
            keepAlive: true  // true表示需要使用缓存  false表示不需要被缓存
        }
    },
    {
        path: '/news',
        name: 'News',
        component: News,
        meta: {
            keepAlive: true
        }
    }
]
export default new Router({routes})
</script>

说明: 
(1) 在Home页面输入框输入“home”,然后通过路由跳转到News页面;
(2) 回到Home页面发现 input 之前输入的"home"依然保留,说明页面信息成功保存在内存中;

keep-alive的作用:keep-alive 是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。

keep-alive的属性:
include: 字符串或正则表达式。只有匹配的组件会被缓存。
exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。

21. vue等单页面应用及其优缺点

优点:

Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件,核心是一个响应的数据绑定系统。MVVM、数据驱动、组件化、轻量、简洁、高效、快速、模块友好。

1、具有桌面应用的即时性、网站的可移植性和可访问性。
2、用户体验好、快,内容的改变不需要重新加载整个页面。
3、基于上面一点,SPA相对对服务器压力小。
4、良好的前后端分离。SPA和RESTful架构一起使用,后端不再负责模板渲染、输出页面工作,web前端和各种移动终端地位对等,后端API通用化。
5、同一套后端程序代码,不用修改就可以用于Web界面、手机、平板等多种客户端;

缺点:

不支持低版本的浏览器,最低只支持到IE9;
不利于SEO的优化(如果要支持SEO,建议通过服务端来进行渲染组件);
第一次加载首页耗时相对长一些;
不可以使用浏览器的导航按钮,需自行实现前进、后退。

22. vue中子组件调用父组件的方法

Vue中子组件调用父组件的方法,这里有三种方法提供参考

第一种方法是直接在子组件中通过this.$parent.event来调用父组件的方法

<!-- App.vue -->
<template>
  <div id="app">
    <Child />
  </div>
</template>
<script>
import Child from '@/components/Child'
export default {
  name: 'App',
  components: {
    Child
  },
  methods: {
    fatherMethod() {
      console.log('测试');
    }
}
</script>
<!-- Child.vue -->
<template>
    <div id="child">
        <button @click="childMethod()">点击</button>
    </div>
</template>
<script>
    export default {
        name: 'child',
        data() {
            return {
                msg: '子组件child'
            }
        },
        methods: {
            childMethod() {
                this.$parent.fatherMethod()
            }
        }
    }
</script>

第二种方法是在子组件里用$emit向父组件触发一个事件,父组件监听这个事件就行了。

<!-- App.vue -->
<template>
  <div id="app">
    <Child @fatherMethod="fatherMethod" />
  </div>
</template>
<script>
import Child from '@/components/Child'
export default {
  name: 'App',
  components: {
    Child
  },
  methods: {
    fatherMethod() {
      console.log('测试');
    }
}
</script>
<!-- Child.vue -->
<template>
    <div id="child">
        <button @click="childMethod()">点击</button>
    </div>
</template>
<script>
    export default {
        name: 'child',
        data() {
            return {
                msg: '子组件child'
            }
        },
        methods: {
            childMethod() {
                this.$emit('fatherMethod');
            }
        }
    }
</script>

第三种是父组件把方法传入子组件中,在子组件里直接调用这个方法

<!-- App.vue -->
<template>
  <div id="app">
    <Child :fatherMethod="fatherMethod" />
  </div>
</template>
<script>
import Child from '@/components/Child'
export default {
  name: 'App',
  components: {
    Child
  },
  methods: {
    fatherMethod() {
      console.log('测试');
    }
}
</script>
<!-- Child.vue -->
<template>
    <div id="child">
        <button @click="childMethod()">点击</button>
    </div>
</template>
<script>
    export default {
        name: 'child',
        data() {
            return {
                msg: '子组件child'
            }
        },
        props: {
            fatherMethod: Function,
            default: null
        },
        methods: {
            childMethod() {
                if (this.fatherMethod){
                    this.fatherMethod();
                }
            }
        }
    }
</script>
23. package.json的文件解析

name:项目名称
version:项目版本号
description:描述信息,有助于搜索
scripts:支持的脚本,默认是一个空的 test
private:公有私有
keywords:关键字,有助于在人们使用 npm search 搜索时发现你的项目
author:作者信息
license:证书信息(默认是 MIT)
dependencies:在生产环境中需要用到的依赖
devDependencies:在开发环境中用到的依赖,上线打包后的代码是不存在的
engines:node和npm的版本要求
browserslist:浏览器要求

24. vue 全局变量和函数的使用
  1. 首先在src下创建global文件夹,创建global_data.js
const url = 'http://www.baicu.com'
const name = 'zhangsan'

// 暴露变量
export default {
  url,
  name
}
//或者
// module.exports = {
//  url,
//  name
// }
  1. 引用(局部引用,全局引用)
// 全局变量的局部全局引入
// App.vue引用   哪个页面需要哪个页面引入(局部)
import GLOBAL from '@/global/global_data'
export default {
  name: 'App',
  data() {
    return {
      url: GLOBAL.url,
    }
  }
}

// main.js 引入 (全局)
import globalData from '@/global/global_data'
// 挂载vue原型
Vue.prototype.GLOBAL = globalData 

// App.vue 使用
export default {
  name: 'App',
  data() {
    return {
      url: this.GLOBAL.url,
    }
  }
}

// 全局函数的引入
// 第一种方法
// main.js 直接绑定
Vue.prototype.global_fun1 = function() {
  return console.log('fun1');
}
// App.vue 页面输出
export default {
  name: 'App',
  mounted() {
    this.global_fun1();   // 打印 fun1
  }
}

// 第二种方法
// global/新建global_fun.js
import Vue from 'vue'
function fun11(params){
  console.log(params);
}
export default {
  Vue.prototype.global_fun11 = (params) => fun11(params);
}
// next main.js 引入
import globalFun from '@/global/global_fun'
Vue.use(globalFun);
// App.vue 使用
export default {
  name: 'App',
  mounted() {
    this.global_fun11('zhangsan');   // 打印 zhangsan
  }
}
25. vue弹出窗口之后禁止页面滑动

先阻止默认时间,然后给body添加overflow:hidden;

export default {
  methods: {
    stop() {
      var stop = function(event) {
        event.preventDefault();
      }
      document.body.style.overflow = 'hidden';
      document.addEventListener('touchmove', stop, false);  // 禁止页面滑动
    }
    move() {
      var move = function(event) {
        event.preventDefault();
      };
      document.body.style.overflow = '';  //出现滚动条
      document.removeEventListener("touchmove", move, false); //开启页面滑动
    }
  }
}
26. v-for产生的列表,实现active的切换?
<template>
  <ul>
    <li v-for="(item, index) in movieArr" @click="curIndex = index" :class="{actived: index == curIndex}">
        <span>{{item}}</span>
    </li>
  </ul>
</template>
<script>
export default {
  name: 'App',
  data() {
    curIndex: 0,
    movieArr: ['三国', '大人物', '无双']
  }
}
</script>
<style>
.actived {
  color: red;
}
</style>
27. vue实现路由懒加载

懒加载:也叫延迟加载,即在需要的时候进行加载,随用随载。
为什么需要使用懒加载?

像vue这种单页面应用,如果不应用懒加载,运用 webpack 打包后的文件将会异常的大,造成进入首页时,需要加载的内容过多,时间过长,会出现长时间的白屏,即使做了loading也是不利于用户体验,而运用懒加载则可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时

不使用懒加载的路由配置:

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Home from '@/components/Home'
import News from '@/components/News'

Vue.use(Router)

export default new Router({
    routes: [
        {
            path: '/',
            component: Home
        },
        {
            path: '/helloworld',
            name: 'HelloWorld',
            component: HelloWorld,
            meta: {
                keepAlive: true
            }
        },
        {
            path: '/home',
            name: 'Home',
            component: Home,
            // 组件切换时,将状态保存在内存中,防止重复渲染
            meta: {
                keepAlive: true  // true表示需要使用缓存  false表示不需要被缓存
            }
        },
        {
            path: '/news',
            name: 'News',
            component: News,
            meta: {
                keepAlive: true
            }
        }
    ]
})

使用懒加载的路由配置:

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'

Vue.use(Router)

export default new Router({
    routes: [
        {
            path: '/',
        },
        {
            path: '/helloworld',
            name: 'HelloWorld',
            component: resolve => require(['@/components/HelloWorld'], resolve)
        },
        {
            path: '/home',
            name: 'Home',
            component: resolve => require(['@/components/Home'], resolve),
            children: [{
                path: '/detail',
                name: 'Detail',
                component: resolve => require(['@/components/Detail'], resolve)
            }],
            meta: {
                keepAlive: true
            }
        },
        {
            path: '/news',
            name: 'News',
            component: resolve => require(['@/components/News'], resolve),
            meta: {
                keepAlive: true
            }
        }
    ]
})

28. vue-router 的两种模式

hash 模式 和 history 模式

hash 模式:
hash 发生变化之后,url 都会被浏览器记录下来,所以你会发现浏览器的前进后退都可以用了,点击前进、后退,可以跳转页面。

hash模式的工作原理是onhashchange事件,可以在window监听hash的变化。
event 事件里边有两个属性newURL和oldURL。可以通过模拟改变 hash 的值,动态改变页面数据。

// 页面的URL:http://kuayu.lc/hash.html#pink,通过改变 hash 的颜色值,来改变 div 的颜色。
<div id="div1" style="height: 500px;width: 500px;margin: 0 auto"></div>
<script>
  window.onhashchange = function(event){
    let event = event || window.event;
    let hash = location.hash.slice(1);
    document.getElementById('div1').style.backgroundColor = hash
  }
</script>
尽管浏览器没有向服务器发送请求,但页面状态已经和 url 关联起来了,这就是所谓的前端路由,单页应用的标配。

网易云音乐,百度网盘就采用了hash路由,看起来就是这个样子:

  1. 网易云音乐:http://music.163.com/#/friend
  2. 百度网盘:https://pan.baidu.com/disk/home#list/vmode=list

history模式:
把window.history 对象打印出来之后,可以看到里边提供的方法和记录长度(__ proto__ 原型链上)
console.log(window.history);


image.png

前进,后退,跳转操作方法:

  history.go(-2);        //后退2次
  history.go(2);         //前进2次
  history.go(0);         //刷新当前页面
  history.back();        //后退
  history.forward();     //前进

如果不想用 # 的 hash,我们可以用路由的 history 模式。

export default new VueRouter({
  mode: 'history',
  routes: [...]
})

当你使用 history 模式时,URL 就像正常的 url : http://localhost:8080/news

不过这种模式要玩好的话,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://localhost:8080/news1234 (没有路由,访问不到的情况) 就会返回 404,这就不好看了。

为了避免这种情况,你应该在 Vue 应用里面覆盖所有的路由情况,然后在给出一个 404 的组件页面。

export default {
  mode: 'history',
  routes: [
    {path: '*', component: resolve => require(['@/components/NotFound'], resolve)}
  ]
}
29. $router 和 $route 的区别

$router 为 VueRouter 实例,想要导航到不同 URL,使用 $router.push 方法。

$route 为当前 router 跳转对象,里面可以获取 name 、 path 、 query 、 params、meta 等信息。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容

  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 4,989评论 0 29
  • ## 框架和库的区别?> 框架(framework):一套完整的软件设计架构和**解决方案**。> > 库(lib...
    Rui_bdad阅读 2,857评论 1 4
  • vue概述 在官方文档中,有一句话对Vue的定位说的很明确:Vue.js 的核心是一个允许采用简洁的模板语法来声明...
    li4065阅读 7,108评论 0 25
  • 基于Vue的一些资料 内容 UI组件 开发框架 实用库 服务端 辅助工具 应用实例 Demo示例 element★...
    尝了又尝阅读 1,122评论 0 1
  • 前言 您将在本文当中了解到,往网页中添加数据,从传统的dom操作过渡到数据层操作,实现同一个目标,两种不同的方式....
    itclanCoder阅读 25,585评论 1 12