第2节 vue面试题(56道)#
摘讲#
- 02 vue-cli3搭建项目之webpack配置
- 15 vue虚拟dom ***
- 17 vue路由传参问题
- 25 vue hash 和history的区别 ***
- 20 Vue的响应式原理
- 28 v-if v-for 在哪个钩子函数中解析 ***
- 57 初识vue3(了解)
- 58 初识typescript(了解)
- 59 初识webpack
01 插件和组件的区别 **#
Vue组件(component)用来构成你的App的业务模块,它的目标是App.vue。 引入 ,注册,html中作为标签名的形式使用
-
请说下封装 vue 组件的过程?#
答:
- 建立组件的模板,先把架子搭起来,写写样式,考虑好组件的基本逻辑。(os:思考1小时,码码10分钟,程序猿的准则。)
- 准备好组件的数据输入。即分析好逻辑,定好 props 里面的数据、类型。
- 准备好组件的数据输出。即根据组件逻辑,做好要暴露出来的方法。
- 封装完毕了,直接调用即可
-
vue插件
- Vue插件(plugin) 用来增强你的技术栈的功能模块, 它的目标是Vue本身。(插件是对Vue的功能的增强和补充)
- 插件一般需要写成一个独立的js文件,需要安装,需要 引入,需要 use(使用) 插件的封装 ** 从零开始的vue插件封装 - 简书 我封装过tab标签的插件 ,封装过 弹窗的插件,封装过列表的插件,封装过瀑布式布局的插件 暴露的接口(可变的,用户可以向里面输入内容的,选择不同的显示状态的地方) , VUE常用插件库总结__Boboy的博客-CSDN博客_vue插件库
02 vue-cli3搭建项目之webpack配置#
const path = require('path')
module.exports = {
publicPath: './', // 基本路径,配置静态文件的访问路径
outputDir: 'dist', // 输出文件目录
lintOnSave: false, // 是否开启eslint检查
// webpack配置
chainWebpack: (config) => {
},
configureWebpack: (config) => {
if (process.env.NODE_ENV === 'production') {
// 为生产环境修改配置...
config.mode = 'production'
} else {
// 为开发环境修改配置...
config.mode = 'development'
}
Object.assign(config, {
// 开发生产共同配置
resolve: {
// 别名配置
alias: {
'@': path.resolve(__dirname, './src'),
'@c': path.resolve(__dirname, './src/components'),
'@p': path.resolve(__dirname, './src/pages')
}
}
})
},
productionSourceMap: false, // 生产环境是否生成 sourceMap 文件
// css相关配置
css: {
extract: true, // 是否使用css分离插件 ExtractTextPlugin
sourceMap: false, // 开启 CSS source maps?
loaderOptions: {
css: {}, // 这里的选项会传递给 css-loader
postcss: {} // 这里的选项会传递给 postcss-loader
}, // css预设器配置项 详见https://cli.vuejs.org/zh/config/#css-loaderoptions
modules: false // 启用 CSS modules for all css / pre-processor files.
},
parallel: require('os').cpus().length > 1, // 是否为 Babel 或 TypeScript 使用 thread-loader。该选项在系统的 CPU 有多于一个内核时自动启用,仅作用于生产构建。
pwa: {}, // PWA 插件相关配置
// webpack-dev-server 相关配置
devServer: {
open: process.platform === 'darwin',
host: '0.0.0.0', // 允许外部ip访问
port: 8022, // 端口
https: false, // 启用https
overlay: {
warnings: true,
errors: true
}, // 错误、警告在页面弹出
proxy: {
'/api': {
target: 'http://www.baidu.com/api',
changeOrigin: true, // 允许websockets跨域
// ws: true,
pathRewrite: {
'^/api': '' // 重写路径
}
}
} // 代理转发配置,用于调试环境
},
// 第三方插件配置
pluginOptions: {}
}
vue3.0 vue.config.js 配置实战 - 给时光以生命 - 博客园
03 vue webpack打包优化:#
1.babel-plugin-component ,减少js包的大小,将插件(如element-ui)和自己写的js分开打包,按需加载 2.路由懒加载:使用import(/webpackChunkName:"group-foo"/'./Foo.vue') 可以完成按需加载页面,避免首页加载内容过多而导致的白屏问题 3.使用 UglifyPlugin (webpack.optimize.UglifyJsPlugin)对代码进行压缩 4.使用该插件image-webpack-loader 进行图片压缩
1: 引入:
require("image-webpack-loader")
2:配置:
module: {
rules: [
...(config.dev.useEslint ? [createLintingRule()] : []),
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
loader: 'image-webpack-loader',
options: {
bypassOnDebug: true,
}
}
},
5.由于webpack打包后的js过大,以至于在加载资源时间过长。所以将文件打包成多个js文件,在需要的时候按需加载
new commonsChunkPlugin({
name:'charts',
chunks:['commons']
minChunks:function(module){
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0 && ['jquery.js', 'highcharts.js','echarts'].indexOf( module.resource.substr(module.resource.lastIndexOf('/')+1).toLowerCase() ) != -1
)
}
})
}
04 v-model的使用。 ***#
答:v-model用于表单数据的双向绑定,vue其实跟react一样是单向数据流, v-model它就是一个语法糖,这个背后就做了两个操作:
-
v-bind绑定一个value属性;
-
v-on指令给当前元素绑定input事件。
05 $nextTick的使用 ***#
答:当你修改了data的值然后马上获取这个dom元素的值,是不能获取到更新后的值, vue虚拟dom
06 vue初始化页面闪动问题 ***#
答:使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。 首先:在css里加上[v-cloak] { display: none; }。 如果没有彻底解决问题,则在根元素加上style="display: none;" :style="{display: 'block'}"
07 v-show和v-if指令的共同点和不同点? ***#
答: 共同点:都能控制元素的显示和隐藏; 不同点:实现本质方法不同,v-show本质就是通过控制css中的display设置为none,控制隐藏,只会编译一次;v-if是动态的向DOM树内添加或者删除DOM元素,若初始值为false,就不会编译了。而且v-if不停的销毁和创建比较消耗性能。 总结:如果要频繁切换某节点,使用v-show(切换开销比较小,初始开销较大)。如果不需要频繁切换某节点使用v-if(初始渲染开销较小,切换开销比较大)。
08 如何让CSS只在当前组件中起作用? ***#
答:在组件中的style前面加上scoped
09 vue优点? *#
答:轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十kb; 简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习; 双向数据绑定:保留了angular的特点,在数据操作方面更为简单; 组件化:保留了react的优点,实现了html的封装和重用,在构建单页面应用方面有着独特的优势; 视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作; 虚拟DOM:dom操作是非常耗费性能的, 不再使用原生的dom操作节点,极大解放dom操作,但具体操作的还是dom不过是换了另一种方式; 运行速度更快:相比较与react而言,同样是操作虚拟dom,就性能而言,vue存在很大的优势。
10 写一个列表页需要考虑什么 *#
这是个开放性问题 需要在性能上考虑这个问题
- 渲染时列表数据过多考虑分页、考虑做上拉加载更多页
- 列表内容需要封装为组件,在页面调用
- 列表数据传参时需要做参数格式验证
- 列表上有图片时考虑使用图片的懒加载,可以使用插件实现
长列表优化:
- 将 table表格替换成其他标签 ,ul li ;
- 分页和 触底加载下一页;
- onScroll 防抖节流; 需要看一下防抖节流 防抖和节流的区别和实现
11 vue项目打包优化 *#
-
组件按需加载
-
路由懒加载
-
异步组件
-
图片压缩合并
-
cdn加速
-
压缩代码
-
组件按需加载#
这是首先可以优化的点。如果频繁使用了第三方组件/UI库,如我的项目中经常同时使用了 element-ui, vant-ui, mint-ui,echarts等组件库,如果全部引入,项目体积非常大,这时可以按需引入组件。
示例如下:
element-ui
首先,安装 babel-plugin-component:
npm install babel-plugin-component -D
然后,将.babelrc 修改为:
{ "presets": [["es2015", { "modules": false }]], "plugins": [ [ "component", { "libraryName": "element-ui", "styleLibraryName": "theme-chalk" } ] ] }
然后引入部分组件,这样一来,就不需要引入样式了,插件会帮我们处理。
// main.js import Vue from 'vue' import { Dialog, Loading } from 'element-ui' Vue.use(Dialog) Vue.use(Loading.directive) Vue.prototype.$loading = Loading.service // 然后正常使用组件
-
路由懒加载#
这里需要一个插件
vue-router官方推荐syntax-dynamic-import插件,不过它要求同时安装@bable/core^7.0.0,如果你安装了babel-core6,是会有版本冲突的。我的做法如下
npm install babel-plugin-syntax-dynamic-import --save-dev(^6.18.0)
// router.js const login = () => import('@/components/login') const router = new VueRouter({ routes: [ { path: '/login', component: login } ] })
还有一种魔法注释用法: 有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 命名 chunk,一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4)。
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
-
异步组件#
如果组件在页面加载时不需要,只在调用时用到,这时可以使用异步组件的写法。仅仅是引入和组件注册写法不同
// template <test v-if="showTest"></test> // script components: { test: () => import('./test') // 将组件异步引入,告诉webpack,将该部分代码分割打包 }, methods:{ clickTest () { this.showTest = !this.showTest } }
-
图片的压缩合并#
无损压缩图片:https://tinypng.com/
如有可能,将图片制作成精灵图
-
CDN加速#
- 在index.html中引入cdn资源
<head> <link href="https://cdn.bootcss.com/element-ui/2.13.0/theme-chalk/index.css" rel="stylesheet"> </head> <body> <div id="app"> </div> <!-- built files will be auto injected --> <script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js"></script> <script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script> <script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script> <script src="https://cdn.bootcss.com/vue-resource/1.5.1/vue-resource.min.js"></script> <script src="https://cdn.bootcss.com/element-ui/2.13.0/index.js"></script> </body>
- 修改 build/webpack.base.conf.js
module.exports = { context: path.resolve(__dirname, '../'), entry: { app: './src/main.js' }, externals:{ 'vue': 'Vue', 'vue-router': 'VueRouter', 'vuex':'Vuex', 'vue-resource': 'VueResource', 'element-ui':'ELEMENT' }, ... }
- 修改src/main.js src/router/index.js 注释掉import引入的vue,vue-resource
// import Vue from 'vue' // import VueResource from 'vue-resource' // Vue.use(VueResource) // 注释element-ui相关引入,注意如果使用了按需引入,这部分也要去掉
-
压缩代码#
vue-cli已经使用UglifyJsPlugin 插件来压缩代码,可以设置成如下配置:
new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false, drop_console: true, pure_funcs: ['console.log'] }, sourceMap: false })
其中sourceMap: false是禁用除错功能。
如果设为true,在部署包中会生成.map结尾的js文件。它用于在代码混淆压缩的情况下仍可进行调试。这个功能虽好,但会大大增加整体资源包的体积,所以将其禁用。
参考链接:
12 vue怎么做动画 *#
-
Vue 提供了 transition 的封装组件#
在下列情形中,可以给任何元素和组件添加进入/离开过渡
<div id="demo">
<button v-on:click="show = !show"> Toggle</button>
<transition name="fade"> <p v-if="show">hello</p></transition>
</div>
new Vue({
el: '#demo',
data: {show: true}
})
<style>
.fade-enter-active, .fade-leave-active { transition: opacity .5s;}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0;}
</style>
过渡的类名 在进入/离开的过渡中,会有 6 个 class 切换。
(1) v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
(2) v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
(3) v-enter-to:2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
(4) v-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
(5) v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
(6) v-leave-to:2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
-
还可以使用css3的动画效果:#
.bounce-enter-active {animation: bounce-in .5s;}
.bounce-leave-active { animation: bounce-in .5s reverse;}
@keyframes bounce-in {
0% { transform: scale(0); }
50% { transform: scale(1.5);}
100% { transform: scale(1);}
}
-
可以使用 js钩子#
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:leave-cancelled="leaveCancelled"
>
<!-- ... -->
</transition>
methods: {
// --------// 进入中// --------
beforeEnter: function (el) { // ...},
// 当与 CSS 结合使用时 // 回调函数 done 是可选的
enter: function (el, done) { // ... done() },
afterEnter: function (el) { // ...},
enterCancelled: function (el) { // ...},
// -------- // 离开时 // --------
beforeLeave: function (el) { // ...},
// 当与 CSS 结合使用时
// 回调函数 done 是可选的
leave: function (el, done) { // ... done() },
afterLeave: function (el) {// ...},
// leaveCancelled 只用于 v-show 中
leaveCancelled: function (el) { // ... }
}
-
可以引入Velocity#
13 空#
14 vue3新特性#
-
更快#
-
虚拟DOM重写
-
优化slots的生成
-
静态树提升
-
静态属性提升
-
基于Proxy的响应式系统
-
-
更小:#
通过摇树优化核心库体积
-
更容易维护:#
- TypeScript + 模块化
-
更加友好#
跨平台:编译器核心和运行时核心与平台无关,使得Vue更容易与任何平台(Web、Android、iOS)一起使用
-
更容易使用#
- 改进的TypeScript支持,编辑器能提供强有力的类型检查和错误及警告
-
更好的调试支持#
-
独立的响应化模块#
-
Composition API(组合式API)#
Vue性能优化及Vue3.0的新特性 - bob_zb - 博客园
15 vue虚拟dom ***#
- 我们都知道在前端性能优化的一个秘诀就是尽可能少地操作DOM,不仅仅是DOM相对较慢,更因为频繁变动DOM会造成浏览器的回流或者重绘,这些都是性能的杀手
- 现在的框架, 不管是vue还是react都有虚拟dom,虚拟dom是在内存生成一个虚拟的dom对象,来记录对应的真实dom节点的属性和方法,这样避免了直接操作真实dom节点,提高性能
16 vuex *#
vuex 流程
- 在组件中使用dispatch 将状态值分发action;
- 在actions中将 状态值commit提交到 mutations;
- 在mutations中修改store中的状态值;
- 当状态值发生变化时,自动触发render重新渲染页面。
vuex核心概念
- vuex 属性 state action mutation module getter
- vuex action mutation 区别 :action 可以异步, 大数据量的操作;mutation 可以直接更改store中的数据值
- vuex getters 作用 相当于vue组件中的计算属性
- vuex辅助函数 mapState mapAction mapMutation mapGetter
vuex与缓存区别
- vuex刷新后数据就没有了,localStorage刷新后值还存在
- vuex是响应式的,localStorage不是响应式的
- vuex数据持久化 vuex-persistedstate
17 vue路由传参问题#
-
vue从a页面跳到b页面,b页面的值是从a页面带过来的,b页面刷新,a页面带过来的值没有了怎么解决?
答: 使用动态路由传参或者query传参可以解决此问题
-
vue从a页面跳到b页面,操作一番后, 再跳回a页面, 发a页面的值没有, 是怎么回事, 怎么解决?
原因: a页面也是从别的页面跳过来的, 带有参数, 从b页面跳回来的时候没有带参数, 所有会到a页面, a页面的值就没有了
解决方案1: a页面跳到b页面的时候把上个页面传给它的参数都传给b页面, 从b页面回来的时候, 把参数带回来
解决方案2: 使用vuex
18 Vue生命周期 *#
-
什么是 vue 生命周期?有什么作用?#
答:每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做 生命周期钩子 的函数,这给了用户在不同阶段添加自己的代码的机会。(ps:生命周期钩子就是生命周期函数)例如,如果要通过某些插件操作DOM节点,如想在页面渲染完后弹出广告窗, 那我们最早可在mounted 中进行。
-
第一次页面加载会触发哪几个钩子?#
答:beforeCreate, created, beforeMount, mounted
-
简述每个周期具体适合哪些场景#
答:beforeCreate:在new一个vue实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建。在beforeCreate生命周期执行的时候,data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法 create:data 和 methods都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶段中操作 beforeMount:执行到这个钩子的时候,在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的 mounted:执行到这个钩子的时候,就表示Vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。 如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行 beforeUpdate: 当执行这个钩子时,页面中的显示的数据还是旧的,data中的数据是更新后的, 页面还没有和最新的数据保持同步 updated:页面显示的数据和data中的数据已经保持同步了,都是最新的 beforeDestory:Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于可用状态。还没有真正被销毁 destroyed: 这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件已经被销毁了。
-
created和mounted的区别#
答:created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。 mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
-
vue获取数据在哪个周期函数#
答:一般 created/beforeMount/mounted 皆可. 比如如果你要操作 DOM , 那肯定 mounted 时候才能操作.
-
请详细说下你对vue生命周期的理解?#
答:总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。 创建前/后: 在beforeCreated阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,el还没有。 **载入前/后:**在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。 **更新前/后:**当data变化时,会触发beforeUpdate和updated方法。 **销毁前/后:**在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在。 *** Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分:
加载渲染过程 父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
19 vue插槽 ***#
- 在父组件调用子组件时,写在子组件标签中间的的内容,可以传递到子组件的slot标签的相应位置;
- 使用场景:类似于element-ui里面的组件封装,对组件的扩展,
- 插槽分类
- 匿名插槽:没名字
- 具名插槽:有名字
- 作用域插槽:所以作用域插槽是一种子传父传参的方式,解决了普通slot在parent中无法访问child数据的去问题
20 Vue的响应式原理, *#
-
核心原理:#
vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
// Object.defineProperty例子解释 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div> <input type="text" id="input"> <span id="text"></span> <br/><br/> <button onclick="click1()">取值</button> <button onclick="click2()">修改</button> </div> </body> </html> <script> var obj = {}; Object.defineProperty(obj, 'msg', { get: function () { console.log('get') return window.val&&val; }, set: function (newVal) { console.log('set'); val = newVal; document.getElementById('text').innerHTML = val; document.getElementById('input').value = val; } }); document.addEventListener('keyup', function (e) { obj.msg = e.target.value; }); function click1() { let msg = obj.msg; console.log('msg的值:',msg); } function click2() { obj.msg = 'hello'; } </script>
-
整体思路(具体实现)#
vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。实现步骤:
- 在vue框架里编写一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
- 在vue框架里编写一个订阅者Watcher,每一个Watcher都绑定一个更新函数,watcher可以收到属性的变化通知并执行相应的函数,从而更新视图。
- 在vue框架里编写一个解析器Compile,可以扫描和解析每个节点的相关指令(v-model,v-on等指令),如果节点存在v-model,v-on等指令,则解析器Compile初始化这类节点的模板数据,使之可以显示在视图上,然后初始化相应的订阅者(Watcher)。
<!DOCTYPE html> <html lang="en"> <head> <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js"></script> </head> <body> <div id="app"> </div> <script> new Vue({ el: '#app', data: { msg: 'hello', username: '张三' }, template: ` <div> <button @click="handClick">修改msg</button> <button @click="handClick2">修改username</button> <p>{{msg}} {{username}}</p> </div>`, methods: { handClick() { this.msg = 'hi'; }, handClick2() { this.username = '李四'; } } }) </script> </body> </html>
-
vue2和vue3对比#
- Vue32020年9月发布的正式版本
- Vue3支持大多数的Vue2的特性
- Vue3设计了一套强大的组合API替代了Vue2中的option API, 复用性更强了
- 更好的支持TS
- 最主要: Vue3中使用了Proxy配合Reflect 替代了Vue2中Object.defineProperty() 方法实现数据的响应式(数据代理)
- 重写了虚拟DOM, 速度更快了
- 新的组件: Fragment(片段) / Teleport(瞬移) / Suspense(不确定)
- 设计了一个新的教授叫工具, Vite
-
vue3.0响应式原理:#
- Vue3.x是用ES6的语法 Proxy对象来实现的,这个玩意儿也可以实现数据的劫持
- 相比于vue2.x,使用proxy的优势如下
- defineProperty只能监听某个属性,不能对全对象监听
- 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
- 可以监听数组,不用再去单独的对数组做特异性操作
- vue3.x可以检测到数组内部数据的变化 vue2.0与vue3.0 双向数据绑定原理 区别 - HOUY - 博客园
-
mvvm框架(补充了解)#
MVVM是Model-View-ViewModel的简写
-
Model 数据模型,用来存储数据
-
View 视图界面,用来展示UI界面和响应用户交互
-
ViewModel 视图模型, 每一个vue组件的实例都是一个ViewModel
-
-
MVC框架 (补充了解)#
Model-View- Controller的简写, angular.js就是mvc框架, 很多后台语言用的也是mvc架构
- Model 数据模型,用来存储数据
- Controller 控制器
- View 视图界面,用来展示UI界面和响应用户交互
21 vue-router实现路由懒加载( 动态加载路由 )#
vue项目实现路由按需加载(路由懒加载)的3种方式_小胖梅的博客-CSDN博客_vue路由懒加载 答:三种方式 第一种:vue异步组件技术 ==== 异步加载,vue-router配置路由 , 使用vue的异步组件技术 , 可以实现按需加载 .但是,这种情况下一个组件生成一个js文件。 第二种:路由懒加载(使用import)。 第三种:webpack提供的require.ensure(),vue-router配置路由,使用webpack的require.ensure技术,也可以实现按需加载。这种情况下,多个路由指定相 同的chunkName,会合并打包成一个js文件。
22 Vue实现弹窗组件需要暴露哪些接口 ***#
例如:暴露了width、title、确定按钮、取消按钮的事件函数、弹窗的内容,
<div id="app">
<base-dialog width="30%" title="我的标题" :visible.sync="dialogVisible">
<span>我是模态框的主体内容</span>
<span slot="footer">
<button class="btn danger">取消</button>
<button class="btn primary">确定</button>
</span>
</base-dialog>
<button @click="showM">显示模态框</button>
</div>
<!--模板-->
<script type="text/template" id="myDialog">
<div class="myDialog" v-if="visible">
<div id="dialogMain" :style="{'width':width}" >
<div id="dialogHeader">
<span>{{title}}</span>
<span @click="hiddenM">×</span>
</div>
<div id="dialogContent">
<slot></slot>
</div>
<div id="dialogFooter">
<slot name="footer"></slot>
</div>
</div>
</div>
</script>
<script type="text/javascript">
//1.创建模态框组件
Vue.component('base-dialog',{
props:['width','title','visible'],
template:'#myDialog',
methods:{
hiddenM:function(){
//将子组件的模态框的状态值传递给 父组件
this.$emit('update:visible');
}
}
});
/***************************************************/
var vm = new Vue({
el:"#app",
data:{
dialogVisible:false
},
methods:{
showM:function(){
this.dialogVisible =true;
}
}
})
</script>
23 Vue路由 ***#
- 路由创建
- 路由跳转
- 路由传参
- 路由模式(25点)
24 路由守卫,路由钩子 ***#
- 全局钩子 beforeEach(全局前置守卫,如果你的项目中有一个以上的功能需要守卫建议使用 这个) afterEach beforeResolve (解析守卫)
- 某个路由的钩子 beforeEnter
- 组件内钩子
- beforeRouteEnter
- beforeRouteUpdate (2.2 新增)
- beforeRouteLeave
- 参数:from to next
- 路由懒加载
- 子路由
25 vue hash 和history的区别 ***#
-
为什么需要路由#
- 因为现在的项目, 绝大部分都是单页应用(Single page application, 简称spa)
- 单页应用的特点就是"单页", 也就是只有一个html页面, 以前使用location.href进行跳转的日子结束了, 所以就需要一种新的跳转方式
-
前端路由主要有两种实现方法:#
- Hash 路由
- History 路由
-
Hash 路由#
- url 的
hash
是以#
开头,原本是用来作为锚点,从而定位到页面的特定区域。当hash
改变时,页面不会因此刷新,浏览器也不会向服务器发送请求。 - 同时,
hash
改变时,并会触发相应的hashchange
事件。所以,hash 很适合被用来做前端路由。当 hash 路由发生了跳转,便会触发 hashchange 回调,回调里可以实现页面更新的操作,从而达到跳转页面的效果。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body { background-color: gray; } footer { height: 50px; display: flex; justify-content: space-around; position: fixed; bottom: 0; width: 100%; background-color: #fff; align-items: center; } </style> </head> <body> <div id="app"></div> <footer> <a href="#">首页</a> <a href="#cart">购物车</a> <a href="#my">我的</a> </footer> <script> let $app = document.getElementById('app'); window.onhashchange = function (a, b, c) { render(); } function render() { let hash = window.location.hash.slice(1); switch (hash) { case 'my': $app.innerHTML = '<h3>我的</h3>'; break; case 'cart': $app.innerHTML = '<h3>购物车</h3>'; break; default: $app.innerHTML = '<h3>首页</h3>'; } } render(); </script> </body> </html>
-
history路由#
-
HTML5 规范中提供了
history.pushState
和history.replaceState
来进行路由控制。通过这两个方法,可以实现改变 url 且不向服务器发送请求。同时不会像hash
有一个#
,更加的美观。但是 History 路由需要服务器的支持,并且需将所有的路由重定向到根页面。 -
有以下两种方式会改变 url:
-
调用 history.pushState 或 history.replaceState, 给其绑定一个渲染方法, 实现页面的改变;
function push (url) { window.history.pushState({}, null, url); render(); } function render () { console.log('渲染页面'); }
-
点击浏览器的前进与后退, 浏览器的前进与后退会触发
popstate
事件。给事件绑定渲染页面的方法, 实现页面的改变window.addEventListener('popstate', render); function render () { console.log('渲染页面'); }
-
-
- url 的
26 Vue使用函数式组件还是类组件 *#
Vue 函数式组件原理和使用详解_陆小森_红齐飘飘的博客-CSDN博客_vue 函数式组件 ##12. vue页面第一次渲染执行的几个钩子函数 beforeCreate created beforeMounte mounted
27 vue页面跳转时执行那几个钩子, ***#
- beforeCreate
- created
- beforeMounte
- mounted
- beforeDestory
- destoryed
28 v-if v-for 在哪个钩子函数中解析 ***#
当 Vue 处理指令时,v-for 比 v-if 具有更高的优先级 避免 v-if 和 v-for 用在一起必要 永远不要把 v-if 和 v-for 同时用在同一个元素上
// 错误写法
<template>
<ul>
<li v-for="list" v-if="item.flag">{{item.name}}</li>
</ul>
</template>
// 正确写法
<template>
<ul>
<li v-for="list.filter(item=>item.flag)">{{item.name}}</li>
</ul>
</template>
// 正确写法2: 使用computed
<template>
<ul>
<li v-for="list2">{{item.name}}</li>
</ul>
</template>
<script>
export default {
data() {
return {list:[
{flag: tue,name:'aa'},
{flag: false,name:'bb'},
{flag: tue,name:'cc'},
]}
},
computed: {
list2() {
return this.list.filter(item=>item.flag)
}
}
}
</script>
29 vue前端路由原理 路由模式#
history hash html5 历史记录
30 计算属性#
计算属性 watch ,计算属性就是当其依赖属性的值发生变化时,这个属性的值会自动更新,与之相关的DOM部分也会同步自动更新。 计算属性有缓存,计算属性的函数会自动调用。普通函数需要手动触发 计算属性和watch ,异步操作或大数据量操作使用watch 1.watch擅长处理的场景:一个数据影响多个数据 2.computed擅长处理的场景:一个数据受多个数据影响
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.13/vue.min.js"></script>
</head>
<body>
<div id="app">
<ul>
<li>{{sum}}</li>
<li>{{sum}}</li>
<li>{{sum}}</li>
</ul>
<ul>
<li>{{add()}}</li>
<li>{{add()}}</li>
<li>{{add()}}</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
a: 2,
b: 3
},
methods: {
add() {
console.log('methods');
return this.a + this.b;
}
},
computed: {
sum() {
console.log('computed');
return this.a + this.b;
}
}
})
</script>
</body>
</html>
vue中,计算属性 computed 和 watch 的区别 - 简书
31 以下全局属性都是做什么用的 **#
$props $attrs $listeners el $options $refs $watch() $emit $on $off $once
32 vue和jquery的区别 *#
jquery对dom操作 是单向的 vue 使用双向绑定
33 $route $router的区别 ***#
33 $route $router的区别 ***#
$route对象表示当前的路由信息,包含了当前 URL 解析得到的信息。包含当前的路径,参数,query对象等。 $router对象是全局路由的实例,是router构造方法的实例。路由实例方法有: push:跳转到一个新页面,push方法的跳转会向 history 栈添加一个新的记录,当我们点击浏览器的返回按钮时可以看到之前的页面。 go前进或后退 replace:push方法会向 history 栈添加一个新的记录,而replace方法是替换当前的页面, 不会向 history 栈添加一个新的记录
34 vue组件中data为什么必须是一个函数? *#
答:因为JavaScript的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。 组建中的data写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个data,这样改一个全都改了。
35 vue后台项目怎么做拦截 ***#
axios 请求拦截 ,验证token ,防攻击 全局路由守卫,除了登录页面,其他页面都需要守卫 token有过期时间,在后台管理,如果过期了,会跳转到登录页,再重新获取token,token 保存到缓存
36 v-if v-show区别为什么v-show没有else ***#
v-if dom节点改变 少量切换使用 v-show 是css样式修改 大量切换使用show
37 vue常用的修饰符 *#
答:.stop:等同于JavaScript中的event.stopPropagation(),防止事件冒泡; .prevent:等同于JavaScript中的event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播); .capture:与事件冒泡的方向相反,事件捕获由外到内; .self:只会触发自己范围内的事件,不包含子元素; .once:只会触发一次。
38 vue初始化页面闪动问题 ***#
答:使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。 首先:在css里加上[v-cloak] { display: none; }。 如果没有彻底解决问题,则在根元素加上style="display: none;" :style="{display: 'block'}"
39 为什么有时候修改了值,可以打印修改的值,但是页面上不会改变#
由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。尽管如此我们还是有一些办法来回避这些限制并保证它们的响应性。 对于对象: Vue 无法检测 property 的添加或移除 Vue 不能检测以下数组的变动: 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue 当你修改数组的长度时,例如:vm.items.length = newLength 当页面上的值不发生变化时,可以使用 $.set 对象还可以使用 :assign 数组还可以使用:splice Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。push() pop() shift() unshift() splice() sort() reverse() 也有非变更方法,例如 filter()、concat() 和 slice()。它们不会变更原始数组,而总是返回一个新数组。
40 用过哪些vue ui组件 element ui里面的#
41 vue项目首页加载图标和地图插件很慢怎么解决 ??#
42 vue组件传参 *#
父传子 : props接收 子传父: $emit 手动触发自定义事件 (因为 vue组件间传递数据时单向的) 兄弟: bus vuex(我) vue组件传参,调用方法的几种方式_kangkang_95的博客-CSDN博客_vue组件传参vue中8种组件传参方式
- props
/
$emit - $children/ $parent
provide
/inject
provide
/inject
是vue2.2.0
新增的api, 简单来说就是父组件中通过provide
来提供变量, 然后再子组件中通过inject
来注入变量。
概念:
注意: 这里不论子组件嵌套有多深, 只要调用了
inject
那么就可以注入provide
中的数据,而不局限于只能从当前父组件的props属性中回去数据
4.ref
/ refs
5.eventBus 6.Vuex 7.localStorage
/ sessionStorage
8.$attrs
与 $listeners
在vue2.4
中,为了解决该需求,引入了$attrs
和$listeners
, 新增了inheritAttrs
选项。 在版本2.4以前,默认情况下,父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外),将会“回退”且作为普通的HTML特性应用在子组件的根元素上
43 vue的路由守卫,原理 ?#
44 vue的动态组件有哪些,是怎样实现的 ***#
和计算属性一起使用的,组件的名字可以更改的组件 一般的动态组件的外面合一使用keep-alive进行缓存
45 怎样通过refs获取子组件的数据和方法 *#
<template>
<div>
<children ref='ch'>
</children>
<h1 @click="onclick">父组件</h1>
</div>
</template>
<script>
import children from './coms/children'
export default {
data() {
return {}
},
components: {
children
},
methods: {
onclick() {
// 或者 let chil = this.$refs['ch']
let chil = this.$refs.ch
// 父组件可以通过$refs拿到子组件的对象
// 然后直接调用子组件的 methods里的方法和data里的数据
console.log(chil) //子组件对象
console.log(chil.sonData) // 我是子组件的数据
console.log(chil.sonMethod()) // 我是子组件的方法
}
}
}
</script>
46 vue如何创建一个路由表 **#
- 31.1 引入 vue-router
- 31.2 使用 路由 插件 Vue.use(VueRouter);
- 31.3 定义路由表 写路由表中的配置信息path(路径) component(跳转到的组件) name(名称) meta(路由原信息)
const routes = [
{"path":"/","component":recommend},
{"path":"/mymask","component":mymask}
];
- 31.4 创建路由对象 new vueRouter
const router = new VueRouter({
routes:routes
})
47 nextTick的作用 ***#
答:当你修改了data的值然后马上获取这个dom元素的值,是不能获取到更新后的值, 你需要使用$nextTick这个回调,让修改后的data值渲染更新到dom元素之后在获取,才能成功。
48 vue3.0将mixin替换成了Composition API ***#
49 vue项目中哪些部分使用了全局管道符,哪些地方使用了局部的 *#
filter 过滤器 后台项目 ,
50 vue项目中你做过哪些复杂编写,遇到的问题 ,解决方法 *#
- 从详情页返回列表时保存浏览位置 用到keep-alive来缓存页面 当详情页中改变列表数据时,配合keep-alive,需要在vue钩子函数activated中,对数据进行更改 activated keep-alive组件激活时调用。 deactivated keep-alive组件停用时调用。 1.用到keep-alive来缓存页面 2.当详情页中改变列表数据时,配合keep-alive,需要在vue钩子函数activated中,对数据进行更改 3.在从其他页面进入时,页面要重新加载数据。页面从列表进入其他页面(非详情页)时,销毁当前的vue实例。此时需用到组件内的路由守卫,beforeRouteEnter和beforeRouteLeave vue中keep-alive的使用及详解_半度℃温热的博客-CSDN博客_keep-alive详解vue组件的keep-alive - 古兰精 - 博客园
- 路由全局守卫 router.beforeEach(to,from,next) 当从一个路由跳转到另一个路由时触发此守卫,也叫全局前置守卫。 所以它是跳转前触发的。任何路由跳转都会触发。 每个守卫都有三个参数: to:这是你要跳去的路由对象; from:这是你要离开的路由对象; next:是一个方法,它接收参数; next() 跳转 next(flase) 中断跳转 next({path:"/"}) 中断跳转,跳转到一个新的路径
- axios拦截器 使用axios 实现登录功能的流程(拦截器) 先添加拦截器判断, 利用interceptors 调用request ,判断token 是否存在,如果存在,直接跳转
axios拦截器: // 请求拦截,可以将请求的配置进行二次处理。 axios.interceptors.request.use(config=>{ // config 是axios的配置信息. // console.log(config); if(localStorage.token){ config.headers = { authorization:localStorage.token //将 token的值在 header中传给后台,在后台判断token是否正确 } } store.commit("CHANGE_LOADING",true); config.url = "/ele"+config.url; return config; }) // 响应拦截 数据没出来时的旋转小图标,报错码对应的报错信息的提示,正确获取数据,返回 promise对象 axios.interceptors.response.use(({data})=>{ console.log(44444444); // 返回的值即是axios得到的值 store.commit("CHANGE_LOADING",false); if(data.ok === 2 || data.ok === 3){ store.commit("OUT_LOGIN"); }else{ return data; }
- css引用图片打包后找不到文件资源的问题 css引入图片再打包后,style-loader无法设置自己的publicPath,所以只要改变style-loader中的publicPath即可,一行代码即可以搞定, 找到build/util.js文件中ExtractTextPlugin的css路径,手动添加publicPath参数, if (options.extract) { return ExtractTextPlugin.extract({ use: loaders, publicPath: '../../', fallback: 'vue-style-loader' }) } else { return ['vue-style-loader'].concat(loaders) } 重新build一次,问题解决了
- mixin 可以提高代码的复用性,同时减少代码的耦合度,但是另一方面给代码维护造成了不小的困扰,用的时候需要衡量其使用频率。 比如后台项目:添加 、修改,下拉级联菜单,数据,请把它放到 mixin中,在添加和修改页面中调用就可以了 前台:好多个页面都有 筛选、分页、上拉夹杂爱更多、排序,只要功能是重复出现的,请封装到mixin中 3.0时用新的 Composition API 提供了更好的解决方案
- 多了解一下vue的生命周期,包括公开的以及未公开的,必要时可以方便写个vue插件,在生命周期函数中注入新的功能,包括新的钩子函数,或者新的业务集成。比如:keep-alive的两个钩子
- 如有必要,beforeDestory钩子中手动回收一些变量或者注销一些事件,培养自己垃圾回收的意识,以免出现内存问题。如:定时器、事件的解除绑定、轮播的停止等
- 状态需要统一管理时考虑使用 vuex ,项目中哪个地方使用了?购物车、用户登录后的数据(比如:用户名、用户权限、用户的相关信息,)、 左侧菜单的打开或关闭,从后台获取的异步数据
- mounted钩子函数中请求数据导致页面闪屏问题 其实就是加载时机问题,放在created里会比mounted触发早一点,如果在页面挂载完之前请求完成的话就不会看到闪屏了
- el-input手动获取焦点问题 情景:输入框一开始是隐藏的,点击按钮显示输入框并获取焦点 把手动获取焦点那段代码写在nextTick(() => { this.$refs.searchBox.focus() })
vue项目中遇到的问题汇总 - 简书该回答已被删除 - 知乎
51 vue中v-html会导致哪些问题 *#
你的站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。 可能会导致xss攻击 V-html更新的是元素的 innerHTML 。内容按普通 HTML 插入, 不会作为 Vue 模板进行编译 。 但是有的时候我们需要渲染的html片段中有插值表达式,或者按照Vue模板语法给dom元素绑定了事件。 在单文件组件里,scoped 的样式不会应用在 v-html 内部,因为那部分 HTML 没有被 Vue 的模板编译器处理。如果你希望针对 v-html 的内容设置带作用域的 CSS,你可以替换为 CSS Modules 或用一个额外的全局 style元素手动设置类似 BEM 的作用域策略。 后台返回的html片段,以及css样式和js,但是返回的js是不执行的,因为浏览器在渲染的时候并没有将js渲染,这时要在$nextTick中动 态创建script标签并插入 vue ---根据白名单过滤HTML(防止XSS攻击)_logytar的博客-CSDN博客_vue xss
52 Vue的路由实现:hash模式 和 history模式 ***#
hash模式:在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取; 特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。 hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.xxx.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。 history模式:history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。 history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.xxx.com/items/id。后端如果缺少对 /items/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”
53 vue解决跨域问题的方法: ***#
vue项目解决跨域: proxy ,但是打包后不能用 ;打包后需要在后台设置 nginx vue中解决跨域问题 - 火星黑洞 - 博客园
54 vue项目的兼容性问题处理 **#
pc: 1、ES6语法不支持 解决方法: 引入babel-polyfill npm install --save bable-polyfill webpack.base.conf.js中修改为 app: ['event-source-polyfill', 'babel-polyfill', './src/main.js'] main.js 中引入 import 'babel-polyfill'; 2、GET非首次请求时,IE默认使用缓存而不是去后台请求 解决方法: 在request拦截时,加时间戳 service.interceptors.request.use(config => { // Do something before request is sent // // 时间戳 if (config.method === 'get') { config.params = { t: Date.parse(new Date()) / 1000, ...config.params } } return config; }, error => { // Do something with request error console.log(error); // for debug Promise.reject(error); }) 3、上传文件时,文件类型检查。如果为.apk文件,则file.type为" ".而jpg/png等文件正常 导致上传apk文件时,会报类型检查错误 解决方法: export function validateApk(file) { if (file.type === 'application/vnd.android.package-archive') { return true; } else { if (file.name.substring(file.name.lastIndexOf('.') + 1) === 'apk') { return true; } } return false; } 4、上传文件时,后台读取file.getName或者file.getOriginalName为全路径名称 解决方法: 后台去处理,如果为全路径,则进行字符串截取 IE目前已经放弃了自己的独特化,正一步步迎入互联网的主流怀抱。但迫于有用户存在,还是要兼容到IE8,9, 以上。 下面聊一下如何在vue框架中兼容IE 1.首先在index.html 问题:Vue2.0的官方脚手架工具构建的项目,chrome中跑一直没有问题,但ie打开出现了bug: 原因:Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的 API ,比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转码。为了解决这个问题,我们使用一种叫做 Polyfill (代码填充,也可译作兼容性补丁) 的技术。 简单地说,polyfill即是在当前运行环境中用来复制(意指模拟性的复制,而不是拷贝)尚不存在的原生 api 的代码。 方案:安装babel-polyfill
步骤
1.安装babel-polyfill
npm install --save-dev babel-polyfill
2.然后再main.js中引入
import 'babel-polyfill'
3.如果也是用了官方脚手架vue-cli,还需要在webpack.config.js配置文件中做各修改,用
module.exports = {
entry: {
app: ["babel-polyfill", "./src/main.js"] // 替换 app: './src/main.js'
}
};
55 如何给vue自定义组件添加点击事件?#
需要在@click后面加上.native,官方对于native的解释为: .native -——监听组件根元素的原生事件
56 vue项目做seo优化 *#
关于vue的seo优化_养只猫的博客-CSDN博客_seo vuevue项目如何做seo优化?_红烧金鱼草的博客-CSDN博客_vue项目seo怎么做
57 初识vue3(了解)#
- 创建vue3项目, 还是可以使用vue-cli进行创建, 也可以使用vite进行创建
vue create myapp
// HelloWorld.vue
<template>
<div>
<span>{{ msg }}</span> <button @click="changeMsg">修改msg</button>
</div>
<h3>分类列表</h3>
<ul>
<li v-for="(item,index) in list" :key="item.id" @click="select(index)" :class="{on:index===activeIndex}">
{{ item.name }}
</li>
</ul>
</template>
<script>
import { defineComponent, ref, onMounted } from "vue";
import axios from "axios";
export default defineComponent({
setup() {
// msg相关的操作
let msg = ref("hello");
let changeMsg = () => {
msg.value = "hello world";
};
let activeIndex = ref(0);
let select = (index)=> {
activeIndex.value = index;
}
// 列表相关操作
let list = ref([]);
let getList = () => {
axios.get("http://huruqing.cn:3003/category/all").then(res=> {
list.value = res.data.list;
});
};
onMounted(getList);
return {
msg,
changeMsg,
list,
activeIndex,
select,
};
},
});
</script>
<style>
li {
cursor: pointer;
margin-top:20px;
}
.on {
color: red;
}
</style>
58 初识typescript (了解)#
-
安装ts
npm install -g typescript
-
初识化项目
tsc --init
-
开始自动编译ts文件
tsc -w
-
demos
// 变量 let num: number = 100; num = 200; // num = 'aaa'; // error let str: string = "hello"; let boo: boolean = true; // boo = 20; // error // 数组 let list:Array<number> = [1,10,100] // 函数参数限制 function add(a: number, b: number) { let sum: number = a + b; console.log(sum); } // 返回值限制 function add2(a: number, b: number): number { let sum: number = a + b; console.log(sum); return sum; } // 定义一个新数据的类型 type film = { id:string, name:string, poster:string } let obj:film = { id: 'asdfasdfasdf', name: '速10', poster: 'http://sdfsdf.com/aa.png' } // 接口 interface person{ username:string, age:number, // ?可有可无 addr?:string } let zhangsan:person = { username: '张三', age: 100, addr: '广东深圳' }
59 初识webpack#
- 入口和出口
- loader配置: css-loader和less-loader
- 插件配置
- dev-server配置
- 别名配置
const path = require("path");
var HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: "development",
entry: "./main.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "main-webpack.js",
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: [
{
loader: "style-loader", // creates style nodes from JS strings
},
{
loader: "css-loader", // translates CSS into CommonJS
},
{
loader: "less-loader", // compiles Less to CSS
},
],
},
],
},
resolve:{
alias:{
'@': path.resolve(__dirname,'src')
},
},
plugins: [
new HtmlWebpackPlugin({ filename: "index.html", template: "./index.html" }),
],
devServer: {
open: true, //是否自动打开默认浏览器
port: 9000, // 端口号
},
};