Vue基础知识浅谈

tech2022-08-09  139

mvc和mvvm

mvc和mvvm

都是软件架构思想

mvc (react)

model: 数据保存

view: 用户界面

Controller: 业务逻辑

所有通信都是单向的. view -> controller -> model -> view

mvvm(vue)

model: 数据层

view: 视图层

viewmodel: 视图模型层

view和viewmodel是同步更改的,viewmodel再和model层进行通信

数据流向 都是单向

mvc: view -> controller -> model -> view

mvvm: view <-> viewmodel -><- model

vue中常见的指令

v-for 循环v-if 判断是否成立,它不成立代码不加入v-show 是否显示,显示后display为block,如果后面不成立变为nonev-bind 绑定变量 简写:v-on 事件 简写@v-else 如果v-if不成立,这个就成立v-else-if 再次判断v-model 绑定一个变量和当前表单的值绑定v-html 解析标签v-text 不解析标签v-once 只运行一次v-slot 插槽v-pre 不解析标签包裹中的{{变量}},这个变量不解析v-cloak 防止闪烁,在生命周期mounted前,变量在标签内无实际数据,这个可以防止在未有数据之前显示,而是有了数据后再显示出来

v-if和v-show的区别和场景,v-html和v-text的区别

v-if和v-show

区别:

1.手段:v-if是通过控制dom节点的存在与否来控制元素的显隐;v-show是通过设置DOM元素的display样式,block为显示,none为隐藏;

2.编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换;

3.编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译(编译被缓存?编译被缓存后,然后再切换的时候进行局部卸载); v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素保留;

4.性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗;

场景:

如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好

v-html和v-text

v-text和{{}}表达式渲染数据,不解析标签。

v-html不仅可以渲染数据,而且可以解析标签。

vue生命周期

初始化事件,生命周期

beforeCreate

注入数据,初始化响应式数据

cteated

是否有el和template选项

beforeMount

将数据挂载到模板中,将虚拟DOM转成真实dom

mounted

数据改变时触发,dom的更新前后

beforeUpdate

updated

组件销毁的时候触发

beforeDestroy

destroyed

activated

缓存组件被激活时调用

deactivated

缓存组件被停用时调用

errorCaptured

子孙组件出错时调用

计算属性,方法,侦听器的区别

计算属性有缓存,方法无缓存,所以只有在数据发生变化的时候,计算属性才行重新执行

watch适合处理的场景是,侦听一个数的变化,当该数据变化,来处理其他与之相关数据的变化(该数据影响别的多个数据) computed适合处理的场景是,获得一个值或者结果,该结果受其他的依赖的影响。(一个数据受多个数据影响)

描述一下插槽,过滤器和混入

Mixin混入:把各个组件下相同的js部分提取出来,分发给每一个用到的组件,这样可以减少代码量进行优化,但是分发到各个组件下的数据都是相互独立的 全局的mixin不需要在vue实例下进行mixins=[mixin] ,局部的要

//全局的mixin,不需要在实例vue里进行mixins=[mixin]

Vue.mixin({ methods: { hand() { console.log(1) } } })

//局部

const mixin = {

data() { return { pageNum: 1, pageCount: 10 } }, created() { console.log("mixin") } }

插槽:在子组件调用处的中间插入HTML的内容,叫做插槽

-具名插槽:在子组件分发插槽处,寻找父组件对应的插槽名字,把相应的HTML内容渲染到子组件中,注意HTML结构,如果不写名字,默认名字为default

-作用域插槽:子组件的数据传递给父组件时,使用作用域插槽

过滤:将传入的数据进行改变在输出

什么是前端路由,传统的路由实现?

一个url与相应的处理程序之间的映射关系

根据不同的url地址展示不同的内容或者页面

因为vue是个spa(单页面应用,只有一个html文件)

监听hashchange事件

vue-router

vue路由有哪几种模式,有什么区别

三种 hash模式(hashchange事件) 他带#号,用起来比较好用,比较丑 history模式(html5实现) 不带#号,比较好看,需要后端配合 abstract 在 Weex 环境中使用

什么是嵌套路由,动态路由和路由重定向 嵌套路由:如果一个页面内点击跳到下一个地址,但是页面没有进行跳转,那么这个跳转的路由写在当前路由下,作为child路由 动态路由:- 例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果 - 动态路径参数 以冒号开头 path: ‘/detail/:id’ 路由重定向:redirect 重定向也是通过 routes 配置来完成,可以从一个url重定向到另一个url { path: '/', // redirect是重定向 redirect: '/index', }, - 路由传参怎么做?

通过动态路由做 - 描述一下路由守卫

全局前置守卫

const router = new VueRouter({ … }) router.beforeEach((to, from, next) => { // … })

to: Route: 即将要进入的目标 路由对象 from: Route: 当前导航正要离开的路由

全局后置钩子

router.afterEach((to, from) => { // … })

路由独享守卫, 只有在这个路由里面做守卫

beforeEnter: (to, from, next) => { // … } 写在路由内部的

组件内的守卫

写在.vue文件里面,当作option使用 beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 this // 因为当守卫执行前,组件实例还没被创建 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 this }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 this }

描述一下vuex(从下面几个方向回答)

是做什么的? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

有哪几个部分 -state

mutationsactionsgettersmodule

每个部分都做什么

state

存放全局的状态的获取: this.$store.state.xxx 这样也能修改,但是不推荐,因为无法事件记录变化,并且在严格模式下是无法这样修改的修改: 通过mutations辅助函数: …mapState(), 括号内可以写数组或者对象,写数组的话,名字无法改变,对象的话名字可以自己写;写在computed里面

mutations

写同步方法的,是唯一改变state的地方书写: xxx(state) {} 可以直接调用state调用: this.$store.commit(‘xxx’, payload), payload最好是传对象辅助函数: …mapMutations(), 写在methods里面

actions

写异步方法,在异步方法里面调用mutations的方法书写: xxx(context) {} context是一个对象,可以结构调用: this.$store.dispatch(‘xxx’, payload)辅助函数: …mapActions(), 写在methods里面

getters

相当于vuex里面的计算属性,逻辑复杂且多个组件都要用的时候书写: xxx(state) { return …} 可以直接调用state获取: this.$store.getters.xxx辅助函数: …mapGetters(), 写在computed里面

module

Vuex 允许我们用module将 store 分割成模块,模块化划分,便于管理 const moduleA = { state: () => ({ ... }), mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: () => ({ ... }), mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) store.state.a // -> moduleA 的状态 store.state.b // -> moduleB 的状态 获取state: this.$store.state.a.xxx调用mutations: this.store.commit(‘xxx’) 方法是写在全局的,所以不需要写是哪个模块的,但是如果模块有命名,this.store.commit(‘b/xxx’)

状态的流向(流程图)

辅助函数 辅助函数: …mapState(), 括号内可以写数组或者对象,写数组的话,名字无法改变,对象的话名字可以自己写;写在computed里面 辅助函数: …mapMutations(), 写在methods里面 辅助函数: …mapActions(), 写在methods里面 辅助函数: …mapGetters(), 写在computed里面

组件传参怎么做

父子传参非父子传参 父子组件之间的传参

父传子:

父组件用自定义的属性 子组件用props去接受 props: [‘msg’] this.msg

子传父

父组件用自定义事件,在父组件的template里写子组件 <child @message=“method”> method (val) { console.log(val) }子组件用emit去发布 this.emit(‘message’, 传递的值),这个会自动激发父组件写的自定义事件

你常用的git命令有哪些

init 初始化config 配置 git config --global user.name ‘用户名’ git config --global user.email ‘邮箱’add 提交到暂存区commit 提交到本地仓库push 上传到远程仓库pull 从远程仓库获取git log --graph --pretty=oneline 查看分支记录branch 查看分支 如果加个分支名就会创建一个分支 ; branch -a 查看远程分支fetch --all 获取远程分支名称到本地checkout 切换分支 ; checkout -b 分支名 这样就会创建并且切换merge 合并分支clone + 地址 克隆一个与远程仓库有关联的文件夹status 查看git的状态reset HEAD^ 回退一个版本git reset --hard 版本id 回退到指定版本remote add origin +地址 与远程仓库创建联系git diff 查看版本的差别

如果前端已经开发完成了,后端接口还没有给到,你是怎么做的

使用mock数据 采用fetchmock创建线上接口

TypeScript

typescript它不是一门新的语言,它是一门用来规范js的语言

js依旧是一门弱类型的语言

ts是js的一个超集,广义的js是es,dom,bom,ts是es的超集

比方说强类型,面对对象的开发体系

ts常用在大型项目中,使得代码更加规范,协作更加友好,维护更加方便

特点:

增加了静态类型检查,增加了代码的健壮性 是编写时报错,js是执行时报错 使得重构更加的安全与便捷 多人协作的时候,提高生产力,降低维护成本

常用的类型

string, number, boolean, any, void, never, Array<string> / string[], 枚举, 元组 string | number, interface

在vue里面使用ts

类组件,扩展组件, 函数组件 修饰器

服务端渲染

优势:

更好的SEO 搜索引擎优化 更快的到达时间

劣势:

更高的开发要求 更高的服务器的要求

nuxt.js

vue响应式原理

vue是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的getter,setter,当属性发生改变的时候,将变动发布给订阅者,触发监听回调

由于 JavaScript 的限制,Vue 不能检测数组和对象的变化

vue3.0使用了proxy

浏览器的渲染原理和流程

浏览器将获取的HTML文档解析成DOM Tree(DOM树)。将CSS样式表,解析成CSSOM Tree(CSS树)。将DOM和CSSOM合并为渲染树(rendering tree),attachment渲染树的每个元素经过精确的计算后,给出坐标,laylout。将渲染树的各个节点绘制到屏幕上,painting。

为什么要使用虚拟DOM

虚拟DOM是为了解决浏览器性能问题而被设计出来的。比如有10次循环,虚拟DOM不会立即操作DOM,而是将10次的diff内容保存在一个js对象里面,然后一次性的操作,避免大量无谓的计算操作内存中的js对象的速度显然更快,等更新完后,再将最终的js对象映射成真实的DOM,交由浏览器绘制。

diff操作

数据改变,虚拟DOM也会改变

我们不想重新渲染vdom,我们只想渲染改变的部分,就需要用到diff算法

两个树如果完全比较,时间复杂度是O(n^3),Vue的Diff算法的时间复杂度是O(n),意味着只能平层的比较两棵树的节点,放弃了深度遍历。似乎牺牲了一定的精准性来换取速度,但考虑到前端页面通常不会跨层移动DOM元素,这样做是优先的

采用了同级比较,只有count相同的children进行比较 比较他们的key,进行增加,删除,替换,换位等操作

自定义指令

全局定义:他也可以加修饰符,绑定元素的所有内容,全部在binding里,可以通过判断修饰符的内容进行一些操作

//写法一

Vue.directive(‘focus’, { //定义一个v-focus

// 当被绑定的元素插入到 DOM 中时…… inserted: function(el, binding) { //el指的是绑定的元素 // 聚焦元素 el.focus() } })

//全局的第二种写法

Vue.directive('focus', { bind() {},//bind表示当前指令绑定到该元素身上,立刻触发 // inserted表示绑定的元素已经渲染为真实的dom,并且在页面中已经可以看到 inserted: function(el) { // 聚焦元素 el.focus() } })

局部定义,只能在当前组件使用

directives: {

focus: { // 指令的定义 inserted: function (el) { el.focus() } }

}

最新回复(0)