vuejs 结合文档 面试问答题






谈谈Vue中的MVVM模式

MVVM全称是Model-View-ViewModel
Vue是以数据为驱动的,Vue自身将DOM和数据进行绑定,一旦创建绑定,DOM和数据将保持同步。 ViewModel是Vue的核心,它是Vue的一个实例。Vue实例时作用域某个HTML元素上的这个HTML元素可以是body,也可以是某个id所指代的元素。
DOMListeners和DataBindings是实现双向绑定的关键。DataBindings监听Model层的数据,当数据发生变化,View层的DOM元素随之变化。

v-show和v-if指令的共同点和不同点

达到让元素显示和隐藏的效果,if是惰性的,
if 有更高的切换消耗而 show 有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 show更好,如果在运行时条件不大可能改变则 if 较好。

keep-alive的作用

缓存组件状态或避免重新渲染

Vue中引入组件的步骤

采用ES6的import … from …语法引入组件

Vue.component对组件进行注册,最后使用组件。

指令v-el的作用

作为 Vue 实例的挂载目标

Vue中常用的生命周期钩子函数

beforecreate : 举个栗子:可以在这加个loading事件
created :在这结束loading,还做一些初始化,实现函数自执行
mounted : 在这发起后端请求,拿回数据,配合路由钩子做一些事情
beforeDestroy: 你确认删除XX吗? destroyed :当前组件已被删除,清空相关内容




Vuex的原理和使用方法

是什么?
数据单向流动,组件嵌套过多的时候, 多组件共享同一个State会在数据传递时出现很多问题.Vuex就是为了解决这些问题而产生的。
也就是所有组件的数据中心

一个实例化的Vuex.Store由state, mutations和actions三个属性组成,

• state中保存着共有数据
• 改变state中的数据可以通过mutations方法,同步处理
• 如果要写异步的方法,需要写在actions中

active-class是 vue-router模块的router-link组件

嵌套路由怎么定义
需要在 VueRouter 的参数中使用 children 配置,这样就可以很好的实现路由嵌套

定义vue-router的动态路由?怎么获取传过来的动态参数?

path属性加上/:id。
使用router对象的params.id

至少4种vue当中的指令和它的用法

v-if:判断是否隐藏;v-for:数据循环出来;v-bind:class:绑定一个属性;v-model:实现双向绑定

vue-router是什么?它有哪些组件?
vue用来写路由一个插件。router-link、router-view

导航钩子有哪些?它们有哪些参数?

全局钩子和组件内独享的钩子

参数:
有to(去的那个路由)、from(离开的路由)、next(一定要用这个函数才能去到下一个路由,如果不用就拦截)

vue生命周期的理解

创建前/后: 在beforeCreated阶段,可以加个loading 创建后结束这个loading
创建后,vue实例的数据对象data有了

在mounted阶段,vue实例挂载完成,data.message成功渲染

更新前/后、销毁前后

页面加载会触发哪几个钩子

第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子

DOM 渲染在 mounted 中就已经完成了

vuex的State特性是什么

一、Vuex就是一个仓库,仓库里面放了很多对象。其中state就是数据源存放地,对应于与一般Vue对象里面的data

二、state里面存放的数据是响应式的,Vue组件从store中读取数据,若是store中的数据发生改变,依赖这个数据的组件也会发生更新

三、它通过mapState把全局的 state 和 getters 映射到当前组件的 computed 计算属性中

axios的特点有哪些

一、Axios 是一个基于 promise 的 HTTP 库,支持promise所有的API
二、它可以拦截请求和响应
三、它可以转换请求数据和响应数据,并对响应回来的内容自动转换成 JSON类型的数据
四、安全性更高,客户端支持防御 XSRF

仿豆瓣–案例

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
import vueScrollBehavior from 'vue-scroll-behavior'
import 'normalize.css'

Vue.use(vueScrollBehavior, { router: router })

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  template: '<App/>',
  components: { App }
})
import request from 'superagent'
import jsonp from 'superagent-jsonp'

const state = {
  hotMovies: [],
  newMovies: [],
  topMovies: [],
  movieTags: [
    {
      title: '同时入选IMDB250和豆瓣电影250的电影',
      href: 'https://m.douban.com/doulist/968362/',
      color: '#FFAC2D'
    },
    {
      title: '带你进入不正常的世界',
      href: 'https://m.douban.com/doulist/16002',
      color: '#FF4055'
    },
    {
      title: '用电【影】来祭奠逝去的岁月',
      href: 'https://m.douban.com/doulist/190343',
      color: '#4F9DED'
    },
    {
      title: '女孩们的故事【电影】',
      href: 'https://m.douban.com/doulist/1125971',
      color: '#FFC46C'
    },
    {
      line: true
    },
    {
      title: '科幻是未来的钥匙——科幻启示录【科幻题材】',
      href: 'https://m.douban.com/doulist/4253902',
      color: '#2384E8'
    },
    {
      title: '美国生活面面观',
      href: 'https://m.douban.com/doulist/121326',
      color: '#3BA94D'
    },
    {
      title: '2015终极期待',
      href: 'https://m.douban.com/doulist/37479562',
      color: '#42BD56'
    },
    {
      title: '经典韩国电影——收集100部',
      href: 'https://m.douban.com/doulist/458087',
      color: '#CC3344'
    }
  ]
}

const mutations = {
  getMovie (state, payload) {
    switch (payload.tag) {
      case 'hotMovies':
        state.hotMovies = payload.res
        break
      case 'newMovies':
        state.newMovies = payload.res
        break
      case 'topMovies':
        state.topMovies = payload.res
        break
      default:
        state.hotMovies = payload.res
    }
  }
}

const actions = {
  /**
   * Getting movies
   * q: in_theaters, coming_soon, top250
   * count: 8
   */
  getMovie ({ commit }) {
    request
      .get('https://api.douban.com/v2/movie/in_theaters?count=8')
      .use(jsonp)
      .end((err, res) => {
        if (!err) {
          commit({
            type: 'getMovie',
            tag: 'hotMovies',
            res: res.body.subjects
          })
        }
      })
    request
      .get('https://api.douban.com/v2/movie/coming_soon?count=8')
      .use(jsonp)
      .end((err, res) => {
        if (!err) {
          commit({
            type: 'getMovie',
            tag: 'newMovies',
            res: res.body.subjects
          })
        }
      })
    request
      .get('https://api.douban.com/v2/movie/top250?count=8')
      .use(jsonp)
      .end((err, res) => {
        if (!err) {
          commit({
            type: 'getMovie',
            tag: 'topMovies',
            res: res.body.subjects
          })
        }
      })
  }
}

export default {
  state,
  mutations,
  actions
}
import Vue from 'vue'
import Vuex from 'vuex'

import movie from './modules/movie'
import activities from './modules/activities'
import book from './modules/book'
import subject from './modules/subject'
import group from './modules/group'
import search from './modules/search'
import user from './modules/user'

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    movie,
    activities,
    book,
    subject,
    group,
    search,
    user
  }
})
<template>
  <div class="movie-view has-header">
    <scroller title="影院热映" type="hasCover" :items="hotMovies"></scroller>
    <scroller title="免费在线观影" type="hasCover" :items="topMovies"></scroller>
    <scroller title="新片速递" type="hasCover" :items="newMovies"></scroller>
    <scroller title="发现好电影" type="onlyString" :items="movieTags"></scroller>
    <types></types>
    <download-app></download-app>
  </div>
</template>

<script>
import { mapState } from 'vuex'

import Scroller from '../components/Scroller'
import Types from '../components/Types'
import DownloadApp from '../components/DownloadApp'

export default {
  name: 'movie-view',
  components: { Scroller, Types, DownloadApp },
  data () {
    return {}
  },
  computed: {
    // Getting Vuex State from store/modules/movie
    ...mapState({
      hotMovies: state => state.movie.hotMovies,
      topMovies: state => state.movie.topMovies,
      newMovies: state => state.movie.newMovies,
      movieTags: state => state.movie.movieTags
    })
  },
  methods: {
    // Dispatching getMovie
    getMovie: function () {
      this.$store.dispatch('getMovie')
    }
  },
  created () {
    // Getting movies data on created
    this.getMovie()
  }
}
</script>

<style scoped>

</style>

vuejs重写csdn实例

<template>
    <div>
        <!-- 全局header -->
        <nv-head :page-type="getTitleStr(searchKey.tab)"
                ref="head"
                :fix-head="true"
                :need-add="true">
        </nv-head>

        <section id="page">
            <!-- 首页列表 -->
            <ul class="posts-list">
                <li v-for="item in topics" :key="item.id">
                    <router-link :to="{name:'topic',params:{id:item.id}}">
                    <h3 v-text="item.title"
                            :class="getTabInfo(item.tab, item.good, item.top, true)"
                            :title="getTabInfo(item.tab, item.good, item.top, false)">
                    </h3>
                    <div class="content">
                        <img class="avatar" :src="item.author.avatar_url" />
                        <div class="info">
                            <p>
                                <span class="name">
                                    {{item.author.loginname}}
                                </span>
                                <span class="status" v-if="item.reply_count > 0">
                                    <b>{{item.reply_count}}</b>
                                    /{{item.visit_count}}
                                </span>
                            </p>
                            <p>
                                <time>{{item.create_at | getLastTimeStr(true)}}</time>
                                <time>{{item.last_reply_at | getLastTimeStr(true)}}</time>
                            </p>
                        </div>
                    </div>
                    </router-link>
                </li>
            </ul>
        </section>
        <nv-top></nv-top>
    </div>
</template>

<script>
    // webpack-zepto是模块化后的zepto,可以直接通过import导入使用
    import $ from 'webpack-zepto';
    import utils from '../libs/utils.js';
    import nvHead from '../components/header.vue';
    import nvTop from '../components/backtotop.vue';

    export default {
        filters: {
            getLastTimeStr(time, isFromNow) {
                return utils.getLastTimeStr(time, isFromNow);
            }
        },
        data() {
            return {
                scroll: true,
                topics: [],
                index: {},
                searchKey: {
                    page: 1,
                    limit: 20,
                    tab: 'all',
                    mdrender: true
                },
                messageCount:45,
                searchDataStr: ''
            };
        },
        mounted() {
            if (this.$route.query && this.$route.query.tab) {
                this.searchKey.tab = this.$route.query.tab;

                console.log(this.searchKey.tab)
                console.log(this.$route.query.tab)

            }
            console.log(this.store+'----store')
            // 如果从详情返回并且之前存有对应的查询条件和参数
            // 则直接渲染之前的数据
            if (window.window.sessionStorage.searchKey && window.window.sessionStorage.tab === this.searchKey.tab) {
                alert('go')
                this.topics = JSON.parse(window.window.sessionStorage.topics);
                this.searchKey = JSON.parse(window.window.sessionStorage.searchKey);
                $(window).scrollTop(window.window.sessionStorage.scrollTop)

                this.$nextTick(() => $(window).scrollTop(window.window.sessionStorage.scrollTop));
            } else {
                // alert('get')
                this.getTopics();
            }
            // 滚动加载
            $(window).on('scroll', utils.throttle(this.getScrollData, 300, 1000));
        },
        beforeRouteLeave(to, from, next) {
            // 如果跳转到详情页面,则记录关键数据
            // 方便从详情页面返回到该页面的时候继续加载之前位置的数据
            if (to.name === 'topic') {
                // 当前滚动条位置
                window.window.sessionStorage.scrollTop = $(window).scrollTop();
                // 当前页面主题数据
                window.window.sessionStorage.topics = JSON.stringify(this.topics);
                // 查询参数
                window.window.sessionStorage.searchKey = JSON.stringify(this.searchKey);
                // 当前tab
                window.window.sessionStorage.tab = from.query.tab || 'all';
            }
            $(window).off('scroll');
            next();
        },
        beforeRouteEnter(to, from, next) {
            if (from.name !== 'topic') {
                // 页面切换移除之前记录的数据集
                if (window.window.sessionStorage.tab) {
                    window.window.sessionStorage.removeItem('topics');
                    window.window.sessionStorage.removeItem('searchKey');
                    window.window.sessionStorage.removeItem('tab');
                }
            }
            next();
        },
        methods: {
            // 获取title文字
            getTitleStr(tab) {
                let str = '';
                switch (tab) {
                    case 'share':
                        str = '分享';
                        break;
                    case 'ask':
                        str = '问答';
                        break;
                    case 'job':
                        str = '招聘';
                        break;
                    case 'good':
                        str = '精华';
                        break;
                    default:
                        str = '全部';
                        break;
                }
                return str;
            },
            // 获取不同tab的样式或者标题
            getTabInfo(tab, good, top, isClass) {
                return utils.getTabInfo(tab, good, top, isClass);
            },
            // 获取主题数据
            getTopics() {
                let params = $.param(this.searchKey);
                $.get('https://cnodejs.org/api/v1/topics?' + params, (d) => {
                    this.scroll = true;
                    if (d && d.data) {
                        d.data.forEach(this.mergeTopics);
                    }
                });
            },
            mergeTopics(topic) {
                if (typeof this.index[topic.id] === 'number') {
                    const topicsIndex = this.index[topic.id];
                    this.topics[topicsIndex] = topic;
                } else {
                    this.index[topic.id] = this.topics.length;
                    this.topics.push(topic);
                }
            },
            // 滚动加载数据
            getScrollData() {
                if (this.scroll) {
                    // alert('scroll')
                    let totalheight = parseInt($(window).height(), 20) + parseInt($(window).scrollTop(), 20);
                    if ($(document).height() <= totalheight + 200) {
                        this.scroll = false;
                        this.searchKey.page += 1;
                        this.getTopics();
                    }
                }
            }
        },
        watch: {
            // 切换页面
            '$route' (to, from) {
                // 如果是当前页面切换分类的情况
                if (to.query && to.query.tab) {
                    this.searchKey.tab = to.query.tab;
                    console.log(to.query.tab+'8888888888888888888888')
                    this.topics = [];
                    this.index = {};
                }
                this.searchKey.page = 1;
                this.getTopics();
                // 隐藏导航栏
                this.$refs.head.show = false;
            }
        },
        components: {
            nvHead,
            nvTop
        }
    };
</script>

猜你喜欢

转载自blog.csdn.net/kingrome2017/article/details/80511258