node开发
一、Script代码区域:
1.必须有 export default{}, 哪怕没有任何代码也要写。
1 <script type="text/ecmascript-6"> 2 import MiNav from "../../components/mi-nav" 3 export default { 4 name: "Prodile", 5 components: { // 引入非页面级组件 6 "mi-nav": MiNav, 7 } 8 } 9 </script>
2. name 节点:这个节点也可以没有,但是最好养成一个习惯(要写上,这个会对你调试错误的时候非常有帮助)
这个节点起名字一定要用 Pascal 命名法;
3.Components 节点: 注册当前组件使用的子组件。以便在template中使用
注册名最好使用 Pascal 命名法
4. props 节点: 对外公开属性,便于父组件向当前组件传值,对外公开属性名一定要使用Pascl 命名法则,父组件在传值
的时候要使用 短横线命名法传值
距离说明: 组件对外公开属性
JS内容 简写 props:{ show:{ type:Boolean, required:true // show 是必须传的,控制弹窗是否显示 }, text:{ type:String, required:true // text 是必须传的,内容 } }, html内容 <div class="mi-dialog" @click.self="close" v-show="show" > <div class="mi-dialog-content" :class="align"> <!-- 真正显示的内容,由父级传参 --> <!-- vue规定接收内容的标签(占位符)slot 插槽 将来会被内容替代 --> <slot></slot> </div> </div> 父亲调用
1 A组件对外公开属性{props: [‘isShow’]} //在这个地方的命名
2 B组件在模板中使用A组件并通过isShow 来传值如:<A组件 :difis-show=’true’></A组件>
但是在写代码的时候 要使用上面 那个简写。
5.Data 节点: 除了根实例以外的组件定义的data时,一定要一个函数返回一个对象,
把组件要展示的数据和组件完成某个功能需要的驱动数据放在返回的对象中保存起来,
组件的template就可以无条件使用这个对象里面的数据了
需要的驱动数据放在的返回的对象保存起来,
6.computend 节点:计算属性: 页面中要展示的数据或者驱动功能的数据 ,不是在data中直接获取的,并且不是一目了然的数据,而实需要一定的逻辑计算或处理才能能到间接的数据,这时候可选用计算属性(案例就是项目二的购物车)
计算属性从定义上来说是一个函数,但是在template使用上来说就是一个普通的函数,不用加()
直接可以满足绝大部分的需求 ,同时也有一个缺点 就是不能传参参与计算。
应对需要传参计算的时候就完了,所以计算属性可以返回一个函数,我们可以在返回的函数中,接收参与计算的参数,这时计算属性在调用起来就是函数;
参与计算的数据可以来自 props ,可以来自data,可以来自computed
1 // 计算属性:使用方法相当于data里的数据 2 computed:{ 3 // 计算属性可以按照已给的数据,根据一定的逻辑计算需要显示的数据 4 // 当我们页面中需要显示的数据,或者完成某个功能需要用到的数据,无法直接获得,要 5 按照一定的逻辑计算时,我们应当采用计算属性 6 // 定义计算属性的函数必须显示(明显)的return一个值 7 // 计算属性看起来是一个函数,但是使用方法像data中的数据一样 8 // 计算属性的值是根据别的值算出来的,别的值称为计算属性的 '依赖数据' 9 // 计算属性的优势在于:依赖数据变了,计算属性会自动重新计算自身的新值,依赖数据 10 不变,还是使用之前的值 11 // 对于全选反选:因为计算属性的特性,只要一个依赖数据(单选按钮)变了, 12 isAllCheck(全选)就会改变,所以先存值 13 // 计算属性的值只能用不能直接被改,要改的话以修改计算属性的依赖数据来改变计算属 14 性的值 15 amount:function() { 16 var result = 0; 17 this.list.forEach( item => { 18 // 两个可能一个都不满足 19 // 处于非编辑状态并且按钮被选中的数量加起来 20 if( (!this.isEdit) && item.checked1 ) result += item.count; 21 // 处于编辑状态并且按钮被选中的数量加起来 22 if( (this.isEdit) && item.checked2 ) result += item.count; 23 } ) 24 return result; 25 },
26 isAllCheck:function() { 27 // 单选控制全选 28 if( this.isEdit ){ 29 // every 如果元素全部满足条件(与条件进行比较都为真),则返回真 30 return this.list.every( item => item.checked2 ) 31 }else{ 32 return this.list.every( item => item.checked1 ) 33 } 34 } 35 } 36 })
计算属性使用p 标签来进行 映射数据
1 <template>
<div>
//从而及进行显示
<p class="empty" v-text="info" ></p>
</div>
</template>
<script>
computed:{
2 info() { 3 if(this.isLoading) return "加载中.."; 4 else if(this.isTriggerLoadMore) return "放手立即加载.."; 5 else if(this.hasMore) return "上拉加载更多.."; 6 else if(this.listDate.length === 0) return "暂无相关商品,敬请期待.."; 7 else return "已到达底部.."; 8 } 9 },
info:function(){
return 把return的结果 最终返回给标签
}
</script>
7.methods节点:组件需要的所有方法都放在这里定义,
模板template可以无条件使用methods节点的方法,比如点击事件等;
8. Watch节点: 有两个参数:
1.监听任意数据 props, data, computed,路由中的数据,
2.要注意watch比较消耗性能,
3.不要过渡使用,watch的合理使用可以让代码更加清晰优雅
4. 监听到数据发生变化时会执行对应函数中的代码
1 <div> 2 <p>FullName: {{fullName}}</p> 3 <p>FirstName: <input type="text" v-model="firstName"></p> 4 </div> 5 6 new Vue({ 7 el: '#root', 8 data: { 9 firstName: 'Dawei', 10 lastName: 'Lou', 11 fullName: '' 12 },
//最后直接运行。 这个是 v-model里面的数据如果发生变化,就实时发生变化,不需要进行return. 13 watch: { 14 firstName(newName, oldName) { 15 this.fullName = newName + ' ' + this.lastName; 16 } 17 } 18 })
备注:template中使用script代码中的东西,直接使用即可;script代码互相访问一定要记得加this去访问;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
二、开发环境刨析
二.1.
什么是 npm start : 进行运行命令
npm start 命令执行过程中发生了什么事情?
1 npm start 是 npm run start 的缩写 2 3 npm run start 表示间接执行 package.json 文件中的, scripts 节点中的start 键对应的命令! 4 npm start => npm run start => npm run dev => 5 6 webpack -dev secrver --inline --progress --config bulid/webpack.dev.conf.js
npm run build 表示开发完了,产品要上线! 让webpack 把所有的源代码,打包成浏览器读得懂的物理文件。
1.scr 文件中放了我们存放的源代码,我们们在开发过程中使用es6的开发语言进行开发,这个开发之后是一个复杂的内容,而我们这些代码是浏览器都不懂的:
既然浏览器都不懂,为什么运行调用的时候却可以查看正常的效果哪?
2.webpack 是一个第三方包,这个包非常重要,这个包的主要作用:用其他许许多多的第第三方包把我们所
写的浏览器都不懂得源代码 ,能够构建成浏览器能读懂的代码!
Webpack:构建编译时候我们的源代码的过程是非常复杂的,webpack工作时候甚至需要有一个对应配置文件,指明了webpack在打包编译时碰到的不同类型的代码如何处理,如何打包,现在我们已经不用考虑这些问题了,因为技术已经成熟,智能化,但作为程序员我们要知道有这个过程。
1 如果单用webpack来打包编译是在痛苦,因为我们程序员每当修改代码时候,
都需要webpack进行打包编译,之后再让浏览器去运行打包后的代码,
不断地重复这个过程,大大增加了开发时间!!! 2 3 优点:在当下,程序开发越来越复杂,体积越来越大,
正因为webpack的存在,我们可以在开发时候进行模块的拆分,组件的拆分,
将模块组件化开发思想发挥到极致 4 缺点:改代码--重新编译打包--刷新浏览器查看最新效果 5 3. webpack-dev-serve也是第三方的包: 6 主要的作用是:命令webpack将我们写的代码编译打包成浏览器读得懂的能够直接运行的代码,
并将这些代码放回内存,而不是生成物理文件;
同时内部创建一个服务器,我们可以通过浏览器访问这个服务器查看内存中的最新代码,
以进行开发调试,源代码在开发过程中不断更新,我们只要保存操作,
webpack-dev-serve马上命令webpack再次重新打包变化的部分,没有变化的不变,
并将最新打包的放到内存,并自动命令浏览器刷新(热加载),
已查看最新效果,大大提高了开发效率。
hot -module-replace
面试中可能会问的问题, 关于 webpack 你知道 是什么吗?
它的配置文件你熟悉吗? 你自己配过吗?
你知道是什么意思吗? 你对 webpack.condig.js 文件是不是熟悉!!!
三、第三方包配置
1 1.Package.json文件中的dependenices中所有的键记录了一个项目依赖的所有第三方文件的清单。Json文件中不允许写注释,
因为json文件中保存的是字符串。 2 2.使用node自带的npm(node package manager)包安装其他的第三方包npm -v全局命令查看本机npm版本 3 3.在相应的项目文件路径中打开命令输入npm install标识在该文件夹目录下的package.Json文件中拉取第三方包自动下载(批量下载)
在该文件夹目录下生成一个node-modules文件夹放下载好的第三方包。npm装包, 4 运行命令 node index.js 进行运行命令 停止的话 ctrk+c 5 缓存文件目录npm config set cache ‘C:/Program Files/nodejs/node-cache’表示所有缓存的目录都会放在这个node-cache中,将来出现装包不顺有错误就将里面的东西删了,重新装即可。
四、Vue实例对象的生命周期钩子函数 所有的对象都有
1 1. beforeCreate: function() { console.log(‘vue实例对象创建前调用’)}; 没有this 关键字 2 2. created:function() { 3 console.log(‘vue实例对象创建后使用’); 4 //在这里一般会发送Ajax请求数据 5 }; 6 3. beforeMount: function() {console.log(‘vue实例对象挂载前调用’)};
//构造函数.mounted 是new 一个实例 7 4. mounted:function() {console.log(‘vue实例对象挂载后使用’)}; //组件创建完之后 只是放在内存里面 把内存的东西插到dom 中显示出来就是 挂载,只有第一次是挂载,其他次数是更新。 8 5. beforeUpdate: function() {console.log(‘vue实例对象更新前调用’)}; 9 6. updated: function() {console.log(‘vue实例对象更新后调用’)}; //能进行updated 就说明 已经挂载成功了 10 7. beforeDestroy: function() {console.log(‘vue实例对象销毁前调用’)}; 11 8. destroyed: function() {console.log(‘vue实例对象销毁后调用’)} 没有this关键字
在配置路由中使用这个
1 // 创建路有对象,设置整个spa vue程序的路由地图 2 // 有返回值,定义变量接收路由对象的返回值,以便配置vue时使用 3 // path:路由路径 component:对应路由渲染的组件 4 var router = new VueRouter({ 5 routes:[ 6 // 默认跳转(重定向) 7 { path:'/' , redirect:'/category' }, 8 { path:'/home' , component: MiHome }, 9 { path:'/category' , component: MiCategory }, 10 // meta是藏值 藏值的含义是,该页面是否需要token验证 11 { path:'/cart' , component: MiCart , meta:{ needAuth:true } 12 }, 13 { path:'/login' , component: MiLogin }, 14 { path:'/profile' , component: MiProfile }, 15 { path:'/list' , component: MiList }, 16 ] 17 }) 18 // 关于路由要会的 19 // 路由跳转,路由拦截,路由传参,路由 20 // 路由守卫 beforeEach 是在进入每个路由之前都要先判断一次 21 // afterEach 是进入每个路由之后都判断一次 22 // to 是去哪里 from是从哪里来 next是下个页面去哪里,是个函数 23 // beforeEach 里的to返回的数据包含路由的信息以及两个用于传参的对象 query, 24 params 25 // 页面之间传参有两种方式,query适合复杂的,params适合简单的数据 26 router.beforeEach(function(to,from,next){ 27 if(to.meta.needAuth && !sessionStorage.getItem('token')) // 判断 28 如果当前要去的页面需要token,并且没有token,则去登录页 29 next({ path:'/login' , query:{ to } }); // 并把当前页面的信息 30 传给query to 返回的数据整个传给query 31 else 32 next(); 33 })
五、Promis
阻塞: 首先在开发中 比如java c语言 c#语言都是可以实现 阻塞情况的
五阻塞:但是javascript 可能就实现不了这种情况。
1 (1)JavaScript的特点:异步无阻塞 2 无阻塞:不会被障碍(错误)影响 3 若代码出错(或需要消耗时间)则先挪出队列,等其他代码都执行完在 4 ··重新执行该代码 5 所有需要消耗时间执行的任务:异步任务 6 不需要消耗时间执行的任务:同步任务 7 JavaScript会自动分同步和异步两个队列,并且优先处理同步任务队列 8 比如:setTimeout即使设为延迟0秒也是放进异步任务队列,在同步任务之后执行 9 (2)如果要让JavaScript以阻塞式执行代码 10 会形成地狱回调:为了形成阻塞式执行代码,一层套一层
1 setTimeout( function (){
2 console.log('1')
3 setTimeout( function(){
4 console.log('2')
5 setTimeout( function(){
6 console.log('3')
7 setTimeout( function(){
8 console.log('4')
9 } ,3000)
10 } ,3000)
11 } ,3000)
12 },3000)
1 但是: 上面的方法不易实现,引入会加大数据的操作。 从而造成了负重。
// 要用Promise把原始的setTimeout改造成返回promise对象的版本 cb = callback 2 function mySetTimeout( cb,time ){ 3 return new Promise( function( resolve, reject ){ 4 setTimeout(function(){ 5 cb(); 6 resolve(); 7 },time); 8 } ) 9 } 10 // Promise用另一种方式打破了JavaScript无阻塞的特点,用then语法绑定回调函数的形式,间 11 接实现了代码的阻塞执行 12 mySetTimeout( function(){ console.log('1') } ,3000 ) 13 .then( function(){ return mySetTimeout( function(){ console.log('2') 14 } ,3000 ) } ) 15 .then( function(){ return mySetTimeout( function(){ console.log('3') 16 } ,3000 ) } ) 17 .then( function(){ return mySetTimeout( function(){ console.log('4') 18 } ,3000 ) } )
从而加大用户的体验度 :
.then(response =>{
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve(response);
},1000);
});
})
1 new Promise( function(resolve,reject){ //promise创建的是obj对象里的内容 2 // 一段异步的耗时的任务 这个执行完之后才执行下面 then 里面的东西 3 }) 4 .then( 5 function() { console.log('成功') }, 6 function() { console.log('失败') } 7 ) 8 then只是先提前说明了成功会干什么,失败会干什么,但还没做,要等任务执行完后是什么状态
工作原理:
1 // 工作原理: 2 var obj = { 3 status: "pending", // status状态属性有三个值:pending挂起,rejected失败, 4 fulfilled成功 5 data: undefined, // 携带的数据 6 fulfilledCallback: null, // status从pending变为fulfilled时的回调函数 7 rejectedCallback: null, // status从pending变为rejected时的回调函数 8 then: function( fun1,fun2 ){ 9 this.fulfilledCallback = fun1; 10 this.rerejectedCallback = fun2; 11 }, 12 resolve: function( data ){ 13 this.data = data; 14 this.status = 'fulfilled'; 15 if( typeof this.fulfilledCallback === 'function' ) 16 this.fulfilledCallback( this.data ); 17 }, 18 reject: function( data ){ 19 this.data = data; 20 this.status = 'rejected'; 21 if( typeof this.rejectedCallback === 'function' ) this.rejectedCallback( 22 this.data ) 23 }, 24 execAsyncTask: function( asyncTask ){ 25 asyncTask( this.resolve, this.rejecta ); 26 return this; 27 } 28 } 29 // synchrounous 同步 sync 30 // asynchrounous 异步 async 31 // execute 执行 exec
六: 防抖:
1 减少某一函数的调用频率( 次数 )? 防止点击次数太多,触发太多次事件 2 防抖 => debounce 3 面试问题:简单写一下防抖的函数 4 (同ajax被封装在了$符号下) 5 function debounce( func ,wait ){ // wait 是等待时间 6 var lock = false; 7 return function( args ){ // args 是函数触发对象,为了传给func对应的函数 8 if( lock ) return; 9 lock = true; 10 setTimeout( function(){ lock = false; } , wait ) 11 func.call( this , args ); // 使用call方法是为了能够访问this,真正被调用的是 12 return后面的函数,把该函数的this传给原函数 13 } 14 } 15 $('button').on('click', debounce( function( e ){ } , 1000 )) 16 // 调用debounce()返回的是return后面的函数,click事件执行的是该函数
七、iscroll
使用 iscoll的条件为:
1.首先 托管下面必须只有一个儿子
2.要给的样式设置 这两个属性
1 overflow: hidden; /* iscroll 插件硬性规定 */ 2 touch-action: pan-y; /* 消除iscroll插件的警告 */
如果是 vue 开发的话,就要npm 下载两个东西
1 "imagesloaded": "^4.1.4", 2 "iscroll": "^5.2.0",
然后进行
1 initOrRefreshScroll() { 2 // iscroll 规定在调用new IScroll 代码时必须保证滚动区域完全渲染完毕 3 // 让滚动内容笔滚动容器宽或者高 4 // iscroll 自带边界回弹效果 5 this.$nextTick(() => {// 保证list变化导致的DOM更新已经完毕 6 imagesloaded( this.$refs.scroll,() => { // 保证滚动区域的所有图片加载完毕 imagesLoaded( 区域,() => {} ) 7 this.$nextTick(() => { // 保证滚动区域的所有图片渲染完毕 8 // 为了避免IScroll一直被new 9 if(!this.scroll){ 10 this.scroll = new IScroll( this.$refs.scroll ,{ 11 click: true, // 开启iscroll的点击事件,iscrollmore你是屏蔽的 12 deceleration: 0.003 , // 设置iscroll滚动的阻尼系数,参数区间,改变动画势头的持续时间,默认值0.0006,系数越大惯性越小 13 bounce: false, // 关闭iscroll的边界回弹效果 14 probeType: 2 // 开启iscroll滚动监听,分为123三个级别,级别越高密度越高 15 }); 16 this.scroll.on("scroll",() => { 17 // 考虑到有用户拉上去之后又放回来,也可以不考虑,触发scrollEnd就加载 18 // 实时判断当前滚动位置,有没有触发加载更多 19 // 加载中以及没有更多数据时,返回 20 this.rocketShow = Math.abs(this.scroll.y) >= 150; 21 if( this.isLoading || !this.hasMore ) return; 22 this.isTriggerLoadMore = this.scroll.y === this.scroll.maxScrollY; 23 24 }); 25 // scrollEnd指的是手指松开或者拉到底部 26 this.scroll.on("scrollEnd",() => { 27 // 判断需不需要加载更多 28 if(this.isTriggerLoadMore){ 29 this.isTriggerLoadMore = false; // 复位 30 this.getListData(true); // 传true,设置beginNum 31 } 32 }); 33 }else{ 34 this.scroll.refresh(); 35 } 36 }); 37 }); 38 });
如果是 pC端开发的话
准备工作:
iscroll-probe.js
和 imagesloaded.js
1 function _initAndRefreshScroll() { 2 if (scroll) { 3 scroll.refresh(); //scroll刷新 4 } else { 5 scroll = new IScroll($('.content')[0], { 6 bounce: false, //是否启用边界回弹效果 7 deceleration: 0.003, //设置滚动的阻止系统 8 click: true, //取消滚动区域对click事件的屏蔽 9 probeType: 2 //命令滚动区域试试触发scroll滚动事件 10 }); 11 scroll.on('scroll', function() { 12 // 监听这个事件的主要目的就是为判断用户有没有触发加载更多的操作 13 if(hasMore && !isLoading) { //如果有更多的商品且没有处于loading状态 14 if(this.y === this.maxScrollY) { 15 isTriggerLoadMore = true; 16 $('p.info').text('放手立即加载..'); 17 }else { 18 isTriggerLoadMore = false; 19 $('p.info').text('上拉加载更多'); 20 } 21 } 22 }); 23 scroll.on('scrollEnd', function() { 24 if(isTriggerLoadMore) { 25 isTriggerLoadMore = false; //垂直成false 26 isLoading = true; //进入loading状态 27 getAndShowData(); 28 } 29 }) 30 } 31 32 } 33 // 排序切换 34 $('.order li').on('click', function() { 35 if (isLoading) { 36 // 动态创建一个p标签 37 var $notice = $('<p class="notice">您的操作太频繁了,请稍后再试..</p>').appendTo('body'); 38 setTimeout(function() { 39 $notice.remove(); 40 }, 2000); 41 return; 42 } 43 isLoading = true; // 防止恶意快速点击 44 hasMore = true; // 重置hasMore 45 $('ul.product-list').empty(); // 清空商品列表,为新商品的显示做准备 46 if ($(this).hasClass('active')) { 47 orderDir = !orderDir; 48 $('.order li').toggleClass('desc').toggleClass('asc'); 49 } else { 50 orderCol = $(this).attr('data-col'); 51 $(this).addClass('active').siblings().removeClass('active'); 52 } 53 // 发送ajax请求商品数据并动态展示 54 getAndShowData(); 55 }); 56 // 指定查找 57 $('i.icon-search').on('click', function() { 58 if (isLoading) { 59 // 动态创建一个p标签 60 var $notice = $('<p class="notice">您的操作太频繁了,请稍后再试..</p>').appendTo('body'); 61 setTimeout(function() { 62 $notice.remove(); 63 }, 2000); 64 return; 65 } 66 isLoading = true; // 防止恶意快速点击 67 hasMore = true; // 重置hasMore 68 $('ul.product-list').empty(); // 清空商品列表,为新商品的显示做准备 69 searchName = $('input.search').val(); // 记录用户当前搜索的关键字 70 // 发送ajax请求商品数据并动态展示 71 getAndShowData(); 72 }); 73 74 // 显示切换模式 75 $('i.mode').on('click', function() { 76 $('i.mode').toggle(); 77 $('ul.product-list').toggleClass('list').toggleClass('card'); 78 setTimeout(function() { 79 if(scroll) scroll.refresh(); 80 }, 20); 81 }); 84 //导火索代码 85 getAndShowData(); 86 91 // 动态判断当前页面,决定哪个激活 92 var url = window.parent.location.href; 93 if(url.indexOf('home') !== -1) 94 $('ul.nav>li').eq(0).addClass('active'); 95 else if(url.indexOf('category') !== -1) 96 $('ul.nav>li').eq(1).addClass('active'); 97 else if(url.indexOf('cart') !== -1) 98 $('ul.nav>li').eq(2).addClass('active'); 99 else 100 $('ul.nav>li').eq(3).addClass('active');
html 内容托管
// 初始化或更新iscroll滚动 imagesLoaded($('.content')[0],function() { _initAndRefreshScroll(); //托管 });
八、提示框注意事件:
1.弹窗的思想:
1.首先对alert confirm dialog
2.弹窗的重复性:
3.弹窗的差异性:
各种弹窗的使用:
第一种: dialog的使用:
1 <mi-dialog :show.sync = "loginShow" align="center"> //show 是必须要传的 如果你想自身可以进行关闭的话,就必须要要传 sync 这个 2 <!--这些代码都放在 solt 插槽里面.--> 3 <div class="window-login-box"> 4 <div class="window-login-con"> 5 <p>请登录</p> 6 <div class="btn-box"> 7 <div class="btn-close">取消</div> 8 <div class="btn-sure">确定</div> 9 </div> 10 </div> 11 </div> 12 </mi-dialog>
第二种弹窗的使用:
count的使用:
/* this.$alert("您好"); 就直接使用
九、let(对象.里面的就可以改了) var const (不可以被改变)
三个声明的变量 的周期是不同的。
let声明变量 生命周期用 “离它最近的大括号代码块去衡量”。
for(let i = 0; i<10; i++){
只在 这个{} 里面
}
但是可以修改对象。里面的东西。
//创建
beforeCreate(){
//无法使用this关键字。 因为组件还没有创建
console.log("vue组件创建签调用");
},
created(){
console.log("创建后调用");
/* this.$alert("您好");
//然后调用这个
this.$confirm("要下课了吗?")
.then(()=>{
this.$alert("去吃饭吧")
})*/
this.$loading.show();
setTimeout(()=>{
this.$loading.close();
},5000)
},
//挂载
// 创建后把组件放在内存,渲染到页面的过程就做挂载
//把第一次叫做 挂载 不是第一次叫做更新。
//进入更新和挂载就说名已经渲染完毕。
mounted(){
console.log("挂载后调用");
},
beforeMount(){
console.log("挂载前调用");
},
//更新
//就是domxuan
beforeUpdate(){
console.log("更新前调用");
},
updated(){
console.log("更新后调用");
},
//销毁
beforeDestroy(){
console.log("销毁前调用");
},
destroyed() {
//没有this 关键字
console.log("销毁后调用");
// 移出. dom移出。
}
}