面试被问到Vue想进一步提升那就停下来看一下吧

Vue作为最近最炙手可热的前端框架,其简单的入门方式和功能强大的API是其优点。而同时因为其API的多样性和丰富性,所以他的很多开发方式就和一切基于组件的React不同,如果没有对Vue的API(有一些甚至文档都没提到)有一个全面的了解,那么在开发和设计一个组件的时候有可能就会绕一个大圈子,所以我非常推荐各位在学习Vue的时候先要对Vue核心的所有API都有一个了解。这篇文章我会从实践出发,遇到一些知识点会顺带总结一下。 进入正题,我相信不论什么项目几乎都会有一个必不可少的功能,就是用户操作反馈、或者提醒.像这样(简单的一个demo) 其实在vue的中大型项目中,这些类似的小功能会更加丰富以及严谨,而在以Vue作为核心框架的前端项目中,因为Vue本身是一个组件化和虚拟Dom的框架,要实现一个通知组件的展示当然是非常简单的。但因为通知组件的使用特性,直接在模板当中书写组件并通过v-show或者props控制通知组件的显示显然是非常不方便的并且这样意味着你的代码结构要变,当各种各样的弹层变多的时候,我们都将其挂载到APP或者一个组件下显然不太合理,而且如果要在action或者其他非组件场景中要用到通知,那么纯组件模式的用法也无法实现。那么有没有办法即用到Vue组件化特性方便得实现一个通知组件的展现,那么我们可否用一个方法来控制弹层组件的显示和隐藏呢? 目标一实现一个简单的反馈通知,可以通过方法在组件内直接调用。比如Vue.$confirm({...obj}) 首先,我们来实现通知组件,相信这个大部分人都能写出来一个像模像样的组件,不啰嗦,直接上代码 <template> <div :class="type" class="eqc-notifier"> <i :class="iconClass" class="icon fl"/> <span>{{ msg }}</span> <!-- <span class="close fr eqf-no" @click="close"></span> --> </div></template><script>export default { name: 'Notification', props: { type: { type: String, default: '' }, msg: { type: String, default: '' } }, computed: { iconClass() { switch (this.type) { case 'success': return 'eqf-info-f' case 'fail': return 'eqf-no-f' case 'info': return 'eqf-info-f' case 'warn': return 'eqf-alert-f' } } }, mounted() { setTimeout(() => this.close(), 4000) }, methods: { close() { } }}</script><style lang="scss"> .eqc-notifier { position: fixed; top: 68px; left: 50%; height: 36px; padding-right: 10px; line-height: 36px; box-shadow: 0 0 16px 0 rgba(0, 0, 0, 0.16); border-radius: 3px; background: #fff; z-index: 100; // 层级最高 transform: translateX(-50%); animation: fade-in 0.3s; .icon { margin: 10px; font-size: 16px; } .close { margin: 8px; font-size: 20px; color: #666; transition: all 0.3s; cursor: pointer; &:hover { color: #ff296a; } } &.success { color: #1bc7b1; } &.fail { color: #ff296a; } &.info { color: #1593ff; } &.warn { color: #f89300; } &.close { animation: fade-out 0.3s; } }</style>在这里需要注意,我们定义了一个close方法,但内容是空的,虽然在模板上有用到,但是似乎没什么意义,在后面我们要扩展组件的时候我会讲到为什么要这么做。 ...

August 20, 2019 · 4 min · jiezi

webpack踩坑记录

webpack入门级配置(最新)目前最的正式版本是:4.31.0,推荐使用本地安装,webpack官网-指南1.初始化确认node 的版本号 node -v新建一个项目文件夹 mkdir demo初始化 npm init -y npm 安装 webpack webpack-cli --save-dev在项目文件夹下新建一个src文件夹,src文件夹包含index.js,index.html新建webpack配置文件 webpack.config.jsconst path = require('path');module.exports = { entry:'./src/index.js'. ouyput:{ path: path.resolve(__dirname,'dist'), filename: 'bundle.js', }}安装 webpack-dev-server本地安装webpack-dev-server npm i webpack-dev-server -D找到package.json文件,搜索scripts,添加 "dev": "webpack-dev-server --open --port 3000 --contentBase src --hot"代码此时在命令行运行npm run dev,即可打包文件安装html-webpack-plugin命令行运行npm install --save-dev html-webpack-plugin在webpack配置文件添加配置信息const HtmlWebpackPlugin = require('html-webpack-plugin');plugins:[new HtmlWebpackPlugin({template:'./dist/index.html'})]加载css命令行运行npm install --save-dev style-loader css-loader配置文件配置module:{reules:[{test:/\.css$/,use:['style-loader','css-loader']}]}安装babel-loader命令行运行npm install -D babel-loader @babel/core @babel/preset-env webpack配置文件配置module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } } ]}运行npm install -D @babel/plugin-transform-runtime配置文件use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], plugins: ['@babel/plugin-transform-runtime'] } }使用vue命令行运行 npm i vue -D配置文件配置# const VueLoaderPlugin = require('vue-loader/lib/plugin');# resolve:{ alias:{ 'vue$':"vue/dist/vue.esm.js" } } 安装vue-loader命令行npm install -D vue-loader vue-template-compiler配置文件+ const VueLoaderPlugin = require('vue-loader/lib/plugin');- rules: [ // ... 其它规则 { test: /\.vue$/, loader: 'vue-loader' } ] - plugins: [ // 引入这个插件! new VueLoaderPlugin() ]附上源代码 ...

May 19, 2019 · 2 min · jiezi

详解vue中静态资源的路径问题(深度好文)

前言: node中的全局变量require开始前,咱们先聊聊node中require的用法。您可能觉得这有什么,不就是直接require(url)直接引用吗,如果您这么想,那可就太小看require了。let url = “@/assets/images/carousel/logo.svg"require(url) //报错let url = “logo.svg"require(”@/assets/images/carousel/"+url); //正确很诡异是不是? 我相信你第一次见到后会不自觉的说句f**k。这是因为你修改页面后,webpack进行编译,等待编译完,需要进行工程的打包,然后打包正确,才能热加载运行并刷新页面。如果require中传入的是个变量,它有可能是计算机系统中的任何目录下的任何文件,那么在打包静态资源时它有可能会将你的电脑整个磁盘遍历一遍(它很傻)。所以至少需要给出在哪个路径下,这样才能精确的将那个路径下的对应文件打包,然后在代码运行时,直接用对应文件名生成正则匹配(因为打包后的文件,可能有hash值。不能直接查文件名),找到后,加载到代码中。所以,请记住 尽可能详细的指定require中的路径,然后拼接变量接下来说下打包后的路径问题webpack将项目中的静态资源编译打包后,生成的路径已经不是原来的那个路径了。如src/assets/image/logo.jpg 编译后可能变成dist/public/image/logo.1d997ea3.jpg而通过require(“src/assets/image/logo.jpg”),会自动找到并加载dist/public/image/logo.1d997ea3.jpg文件一、<template>部分的路径处理Vue Loader 在编译单文件组件中的 <template> 块时,它也会将所有遇到的资源 URL 转换为 webpack 模块请求。(这样我们就没必要手动调用require了,而是交给vue-loader处理了)vue-loader默认可以处理的标签/特性的组合如下:{ video: [‘src’, ‘poster’], img: ‘src’, //即img元素上的src属性 source: ‘src’, //source元素上的src属性 image: ‘xlink:href’}面对上面的标签组合,vue-loader会自动进行资源url的转换。转换规则:a、如果路径是绝对路径,会被原样保留。如/src/assets/image/login/title.png//代码<template> <img src="/src/assets/image/login/title.png” alt=""></template>//渲染后html页面<img data-v-70c98a68="" src="/src/assets/image/login/title.png" alt="">//当然这个图片是无法展示的,因为编译后title.png已不在src/assets/image/login下了b、如果路径以 . 开头,将会被看作相对的模块依赖。如 ./titlea.png//代码<img src="./titlea.png" alt="">//渲染后html页面<img data-v-70c98a68="" src="/static/img/titlea.1e9fa570.png" alt="">c、如果路径以 @ 开头,也会被看作模块依赖。如果你的 webpack 配置中给 @ 配置了 alias,这就很有用了。所有 vue-cli 创建的项目都默认配置了将 @ 指向 /src//代码<img src="@/assets/image/login/title.png" alt="">//渲染后html页面<img data-v-70c98a68="" src="/static/img/title.1e9fa570.png" alt="">d、如果路径以 ~ 开头,其后的部分将会被看作模块依赖,既可以加载含有别名的静态资源,又可以加载node-modules中的资源。如//代码<img src="@/assets/image/login/title.png" alt="">//渲染后html页面<img data-v-70c98a68="" src="/static/img/title.1e9fa570.png" alt="">//代码<img src="[npm包名]/xxx/logo.png" alt="">//渲染后的html页面<img data-v-70c98a68="" src="/static/img/logo.2f53e458.png" alt="">二、<style>部分部分的路径处理由于vue-loader在处理style时,采用的是style-loader,所以可能 和上面<template>部分的转换规则不太一样。在vue-loader的内部使用了如下的配置(不一定配置,也有可能通过js直接给rules赋值)://在vue-loader的内部使用css-loadermodule.exports = { module: { rules: [ { test: /.css$/, loader: ‘css-loader’, options: { url: true, //默认选项 }, }, ], },};url为true时,则意味着可以将url中的字符串通过require()加载进来。转换规则//代码<style scoped>.login-wrap { background-image: url("/src/assets/image/login/title.png");}</style>//渲染后css.login-wrap[data-v-70c98a68] { background-image: url(/src/assets/image/login/title.png);}同样不会显示,编译后的路径不是这个b、如果路径以 . 开头,将会被看作相对的模块依赖。如 ./titlea.png//代码<style scoped>.login-wrap { background-image: url("./titlea.png");}</style>//渲染后css.login-wrap[data-v-70c98a68] { background-image: url(/static/img/titlea.1e9fa570.png);}c、如果路径以 ~ 开头,其后的部分将会被看作模块依赖,即可以加载含有别名的静态资源,又可以加载node-modules中的资源。如//代码<style scoped>.login-wrap { background-image: url("[npm包名]/logo.png");}</style>//渲染后css.login-wrap[data-v-70c98a68] { background-image: url(/static/img/logo.e05643fc.png);}//代码<style scoped>.login-wrap { background-image: url("@/assets/image/login/bg.png");}</style>//渲染后css.login-wrap[data-v-70c98a68] { background-image: url(/static/img/bg.1d997ea3.png);}注意: 和上面的<template>相比,唯独少了直接用@开头的方式url("@/assett/logo.png"),所以下面写法是错误的//代码<style scoped>.login-wrap { background-image: url("@/assets/image/login/bg.png");}</style>感谢各位看客的阅读,由于在项目中遇到了这样的困然,再加上同事也经常问我什么原因,故而填坑,以免其他人踩坑。 ...

March 12, 2019 · 1 min · jiezi

vue入门(一):项目搭建

前言我的JS水平比较一般,而且还是跨专业半路出家,因此学习是唯一出路。vue并不是我接触的第一个前端框架,之前学习过angular1.x,觉得不太容易,结果没多久2版本就推出了,一看文档:totally rewrite。WTF???1还没学利索呢,2就重写了?从此抛弃angular。直到后来,公司需要做个管理后台系统,经过一番比较最终选择了vue,原因:angular已拉黑react里的jsx语法一时不容易掌握vue学习成本较低,简单易上手,性能也很优秀二话不说立马上手,我之前的项目都是通过vue-cli创建的,而其中的webpack配置并不特别贴合项目中的要求,由于我之前已经写了webpack系列的博文,所以在这里就从0-1搭建一个vue项目。1. 开始1.1 安装npm install vue vue-router -S在项目中我们使用 .vue 文件进行开发,所以还要安装一些工具:npm install vue-loader vue-style-loader vue-template-compiler -D1.2 整理目录打开我们之前的webpack项目,删除 src 目录下的所有文件,并在其下创建 asset 文件夹,用来放置资源文件;pages 文件夹,来放置我们的页面文件;router 文件夹,路由配置;http 文件夹,ajax请求配置;app.js 入口文件,还有一个 app.vue 文件,如图所示:然后就可以写代码啦………2. 下面正式写代码2.1 认识 .vue 文件这个 .vue 文件是啥呢,官方文档大概是这么说的:在很多 Vue 项目中,我们使用 Vue.component 来定义全局组件,紧接着用 new Vue({ el: ‘#container ‘}) 在每个页面内指定一个容器元素。这种方式在很多中小规模的项目中运作的很好,在这些项目里 JavaScript 只被用来加强特定的视图。但当在更复杂的项目中,或者你的前端完全由 JavaScript 驱动的时候,下面这些缺点将变得非常明显:全局定义 (Global definitions) 强制要求每个 component 中的命名不得重复字符串模板 (String templates) 缺乏语法高亮不支持 CSS (No CSS support) 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏没有构建步骤 (No build step) 限制只能使用 HTML 和 ES5 JavaScript, 而不能使用预处理器,如 Babel文件扩展名为 .vue 的 single-file components(单文件组件) 为以上所有问题提供了解决方法,并且还可以使用 webpack等构建工具。这是一个文件名为 Hello.vue 的简单实例:编写 app.vue 文件:<template> <div> <h1 class=“red”>{{text }} this is main</h1> </div></template><script>export default { data () { return { text: ‘hello world’ } }, mounted () { console.log(‘app is mounted’) }}</script><style> .red { color: red; }</style>编写入口文件 app.js:import Vue from ‘vue’import App from ‘./app.vue’new Vue({ el: ‘#app’, render: function (h) { return h(App) }})2.2 配置webpack在 config 目录下创建 vue-loader.config.js :// vue-loader.config.js module.exports = function (isDev) { return { preserveWhiteSpace: true, extractCss: !isDev, cssModules: { localIdentName: isDev ? ‘[path]-[name]-[hash:base64:5]’ : ‘[hash:base64:5]’, camelCase: true }, hotReload: isDev //根据环境变量生成 }}修改 webpack.config.js :// 引入vue-loader.configconst createVueLoaderOptions = require(’./vue-loader.config’)// 引入VueLoaderPluginconst VueLoaderPlugin = require(‘vue-loader/lib/plugin’)// 修改入口entry: { app: path.join(__dirname, ‘../src/app.js’) }// 修改loaders配置{ test: /.vue$/, loader: ‘vue-loader’, options: createVueLoaderOptions(isDev) }, { test: /.css$/, use: [ isDev ? ‘vue-style-loader’ : MiniCssExtractPlugin.loader, { loader: ‘css-loader’, options: { importLoaders: 1 } }, ‘postcss-loader’ ] }, { test: /.less$/, use: [ isDev ? ‘vue-style-loader’ : MiniCssExtractPlugin.loader, ‘css-loader’, { loader: ‘postcss-loader’, options: { sourceMap: true } }, ’less-loader’ ] }// 添加VueLoaderPluginnew VueLoaderPlugin(),// 修改HtmlWebpackPluginnew HtmlWebpackPlugin({ template: path.join(__dirname, ‘../app.html’), inject: true, minify: { removeComments: true } })至此,所有配置完毕,执行npm run dev如果配置没错,项目就成功跑起来了 ...

February 4, 2019 · 2 min · jiezi

基础知识:vue-cli项目搭建及配置

vue-cli脚手架搭建// 准备 npm install vue-cli -g确保已全局安装node、npm // 下载 vue init webpack my-project下载脚手架项目// 进入 cd my-project // 运行 npm start把服务跑起来 // 访问 localhost:8080// 了解 以下为vue-cli的结构图config/index.js端口// 更改端口port: 3000,打开浏览器// 是否在编译完成后,// 自动打开浏览器访问http://localhost:3000autoOpenBrowser: false, 代理proxyTable: { // 接口跨域 // 解决跨域的问题 ‘/lots-web/**’: { target: ‘http://localhost:8080’ // 接口的域名 }, // 开发环境本地数据挂载 // json数据文件路径:static/mock/index.json ‘/api’: { target: ‘http://localhost:7000’, pathRewrite: { ‘^/api’: ‘/static/mock’ } }}build/webpack.base.conf.js路径配置alias: { ‘vue$’: ‘vue/dist/vue.esm.js’, ‘@’: resolve(‘src’), // styles ‘styles’: resolve(‘src/assets/styles’)} scss预编译// 安装模块:// npm install –save-dev sass-loader// npm install –save-dev node-sass{ test: /.sass$/, loaders: [‘style’, ‘css’, ‘sass’]}修改文件:xxx.vue<style lang=‘scss’ scoped><style>build/utils.jsvariables.scss预编译// 全局引用variables.scss变量文件 // 安装模块:// npm install –save-dev sass-resources-loaderscss: generateLoaders(‘sass’).concat( { loader: ‘sass-resources-loader’, options: { resources: path.resolve(__dirname, ‘../src/assets/styles/variables.scss’) } })variables.styl预编译// 全局引用variables.styl变量文件 // 安装模块:// npm install –save-dev stylus// npm install –save-dev stylus-loaderconst stylusOptions = { import: [ path.join(__dirname, “../src/assets/styles/variables.styl”) ]}return { stylus: generateLoaders(‘stylus’, stylusOptions), styl: generateLoaders(‘stylus’, stylusOptions)}src/main.js初始 主文件import Vue from ‘vue’import App from ‘./App’import router from ‘./router’ // 路由// 设置为 false 以阻止 vue 在启动时生成生产提示Vue.config.productionTip = false new Vue({ el: ‘#app’, router, components: {App}, template: ‘’}) 详细 主文件// 入口 import router from ‘./router’ // 路由import store from ‘./store’ // 状态import api from ‘./utility/api’ // 接口 // 模块 import axios from ‘axios’ // 接口调用import ‘babel-polyfill’ // ie9和一些低版本的浏览器对es6新语法的不支持问题import fastClick from ‘fastclick’ // 延迟300毫秒import VueAwesomeSwiper from ‘vue-awesome-swiper’ // 图片轮播import BScroll from ‘better-scroll’ // 拖动插件 // 公用样式 import ‘styles/reset.css’ // 重置import ‘styles/common.css’ // 公共import ‘styles/border.css’ // 1像素边import ‘styles/iconfont.css’ // 文字图标import ‘swiper/dist/css/swiper.css’ // 图片轮播// 公用组件 import Fade from ‘@/pages/common/fade’ // 显隐过渡import Gallery from ‘@/pages/common/gallery’ // 画廊Vue.component(‘c-fade’, Fade)Vue.component(‘c-gallery’, Gallery) // 全局调用 Vue.use(VueAwesomeSwiper) // 图片轮播Vue.prototype.$scroll = BScrollVue.prototype.$http = axiosVue.prototype.$api = api // 其他 fastClick.attach(document.body) // 为消除移动端浏览器,从物理触摸到触发点击事件之间的300ms延时的问题 // 创建Vue new Vue({ el: ‘#app’, router, store, components: {App}, template: ‘<App/>’})src/App.vuevue入口文件// keep-alive数据缓存 <keep-alive :exclude=“exclude”> <router-view/></keep-alive>data(){ return { exclude: [ ‘Detail’ ] }}// 用法 // 1、如不填,则缓存全部组件// 2、keep-alive include=“City”,缓存name=‘City’的组件// 3、keep-alive exclude=“Detail”,不缓存name=‘Detail’的组件// 生命周期 // 当时用keep-alive的时候,会触发activated和deactivated生命周期// activated 当组件被激活的时候调用// deactivated 当组件被移除的时候调用src/router/index.js路由文件人口// 初始 import Vue from ‘vue’import Router from ‘vue-router’import Home from ‘@/pages/home/home’export default new Router({ routes: [ { path: ‘/home’, component: Home } ])} // 组件和路由路径 import Home from ‘@/pages/home/home’const path = { home: ‘/’} // 路由和组件渲染 routes: [ { path: path.home, component: Home }] // 路由"#“号去除 mode: ‘history’, // 当前路由添加.activelinkActiveClass: ‘active’,linkExactActiveClass: ‘active’, // 切换路由时界面始终显示顶部 scrollBehavior(to, from, savePosition){ return { x: 0, y: 0 }} // vue用$route获取router // $router// 路由:’/detail/:name’ // ‘/detail/lzm’// this.$route.params.name// 路由:’/detail’ // ‘detail?name=lzm’// this.$route.query.name src/store/index.js状态管理文件入口// 状态管理 import Vue from ‘vue’import Vuex from ‘vuex’import state from ‘./state’import mutations from ‘./mutations’import actions from ‘./actions’Vue.use(Vuex)export default new Vuex.Store({ state, mutations, actions}) // 第四步state.js let defaultCity = { id: 1, spell: ‘beijing’, name: ‘北京’}if(localStorage.city){ defaultCity = JSON.parse(localStorage.city) // 字符串转对象}const state = { city: defaultCity}export default state// 第三步mutations.js const mutations = { changeCity(state, payload){ state.city = payload localStorage.city = JSON.stringify(payload) // 当为对象是,要转字符串 }}export default mutations// 第二步actions.js const actions = { changeCity(context, payload){ context.commit(‘changeCity’, payload) }}export default actions// 第一步xxx.vue // template部分:<div @click=“handleClick(item)">{{city}}</div>// script部分:import { mapState, mapActions} from ‘vuex’export default { computed: { …mapState([‘city’]) }, methods: { …mapActions([‘changeCity’]) handleClick(city){} this.changeCity(city) } }}axios$http调用接口// 全局调用 // 修改main.js文件Vue.prototype.$http = axios// xxx.vue文件:this.$http .get(’/api/index.json’, { params: {…} }) .then( fn(data) ).catch( fn(data )); // 局部调用 // xxx.vue文件:import axios from ‘axios’axios.get(’/api/index.json’) .then( fn(data) ) .catch( fn(data) ); // 案例 getHomeData() { this.$http .get(this.$api.home, { params: { name: this.city.name } }) .then(res => { let resData = res.data; if (resData.ret && resData.data) { let data = resData.data this.bannerList = data.bannerList this.iconList = data.iconList this.likeList = data.recommendList this.weekendList = data.weekendList } }) .catch((err) => { console.log(err) })}移动端移动端初始配置// 移动端访问 // 修改package.json文件:–host 0.0.0.0// mac查看ip: ifconfig// windows查看ip: ipconfig// 手机访问地址: ip:7000 // 缩放比例 // 修改文件:index.html<meta minimum-scale=1.0, maximum-scale=1.0, user-scalable=no><meta width=“device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no”> // 初始化样式 reset.css // 1px像素设备不一致 borer.css // 延迟300ms // 模块 fastclick 解决移动端事件延迟300ms// main.js文件加入:fastClick.attach(document.body) // stylus运用 // 模块 stylus stylus-loader 类似scss预编译// xxx.vue文件:style lang=“stylus"iconfont文字图标// 网址 [http://www.iconfont.cn][2] // 步骤 // 选择图标加入购物车 →// 添加到项目 →// 下载到本地 →// 字体和css复制到项目 →// 更改iconfont目录和删除代码 →// 引入iconfont.css →<span class=“iconfont user-icon”>&#x e624;><span>better-scroll拖动使界面滚动// 全局 // 修改main.js文件:import BScroll from ‘better-scroll’Vue.prototype.$scroll= BScrollxxx.vue文件:mounted() { this.scroll = new this.$scroll(elevent); // element为dom或$refs}, // 局部 // xxx.vue文件:import BScroll from ‘better-scroll’this.scrolll = new BScroll(this.$refs.wrapper)// 定位到某个元素 this.scroll.scrollToElement(element) vue-awesome-swiper图片轮播// 网址 [https://www.swiper.com.cn/][3] // 步骤 // 安装模块 vue-awesome-swiper 轮播插件(2.6.7)// 修改main.js:import “swiper/dist/css/swiper.css"Vue.use(VueAwesomeSwiper)xxx.vue文件:<swiper :options=“swiperOption” v-if=“hasBanner”> <swiper-slide v-for=“item in list”> <img :src=“item.imgUrl”> </swiper-slide> <div class=“swiper-pagination” slot=“pagination”></div></swiper>swiperOption: { pagination: ‘.swiper-pagination’, autoplay: 3000, paginationType: ‘fraction’, loop: true}router-link路由链接// router-link组件的active设置 // 全局设置:export default new VueRouter({ linkActiveClass: ‘active’, linkExactActiveClass: ‘active’, routes : [ … 省略 ]});// 局部设置:<router-link :to="‘home’” tag=“li” active-class=“active” exact-active-class=“active” exact><标题router-link>// 加上exact 则遵循路由完全一致模式,该路由下的路径不匹配 // 标准 <router-link :to=”’/detail?name=’ + item.name” tag=“div”></router-link> // 路由跳转 this.$router.push(’/’)、this.$router.replace(’/’) fade过渡动画// template <transition> <slot></slot></transition> // style <style lang=“stylus” scoped>.v-enter, .v-leave-to opacity 0.v-enter-active, .v-leave-active transition opacity .5s</style>// name name=“fade”.fade-entertouch拖动事件// touchstart/touchmove <div class=“letter” @click=“handleClickLetter” @touchstart.prevent=“handleTouchStart” @touchmove=“handleTouchMove” ref=“letter”> <div class=“letter-cont” ref=“letterCont”> <span class=“letter-item” v-for=“item in list” :key=“item”>{{item}}</span> </div></div>methods: { handleClickLetter(e) { const letter = e.target.innerHTML this.$emit(‘change’, letter) }, handleTouchStart() { this.letterHeight = this.$refs.letterCont.clientHeight / this.letterLen this.letterOffsetTop = this.$refs.letter.offsetTop + this.$refs.letterCont.offsetTop }, handleTouchMove(e) { let touchY = e.touches[0].clientY let letterScope = (touchY - this.letterOffsetTop) / this.letterHeight if (letterScope > 0 && letterScope < this.letterLen) { if (this.timer) clearTimeout(this.timer) this.timer = setTimeout(() => { this.letterIndex = Math.floor(letterScope) }, 16) } }}其他组件里name的作用// 1、递归组件会用到// 2、取消缓存的时候会用到// 3、浏览器vue插件显示组件的时候用到子父组件传值// 子组件:handleClick(){ this.$emit(‘change’, value)}// 父组件:<component @change=“handleClick”></component>handleClick(){} $refs// this.$refs.msg 普通元素,引用指向dom:<div ref=‘msg’>Hello, world<div>// this.$refs.child 组件,引用指向组件实例:<c-child ref=‘child’>Hello, world<c-child>$route获取url数据// 1. /detail/:id// /detail/1389435894this.$route.params.id// 2. /detail// /detail?id=1389435894this.route.query.id利用setTimeout节流if(this.timer) clearTimeout(timer);this.timer = setTimeout(()=>{ console.log(‘‘xxx’)}, 16);滚动监听// 1.window.onscroll = this.handleScroll// 2.window.addEventListener(‘scroll’, this.handleScroll)浏览器cookielocalStorage.city = citylocalStorage.clear() ...

January 25, 2019 · 4 min · jiezi