位置: IT常识 - 正文

原生JS实现飞机大战游戏 超详细解析 快来做一个自己玩吧(原生js实现promise)

编辑:rootadmin
原生JS实现飞机大战游戏 超详细解析 快来做一个自己玩吧

推荐整理分享原生JS实现飞机大战游戏 超详细解析 快来做一个自己玩吧(原生js实现promise),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:原生js教程,原生js实现飞机模拟,原生js常用的方法,原生js实现飞机模拟,原生js常用的方法,原生js实现飞机模拟,原生js实现飞机模拟,原生js实现飞机模拟,内容如对您有帮助,希望把文章链接给更多的朋友!

目录

1. 案例分析💨

2. 适配设备 💨

3. 背景滚动💨

4. hero操作💨

5. 敌机的创建与运动💨

6. 子弹的创建与运动💨

7. 碰撞检测💨

8. 统计得分💨

9. 设置开始与结束界面💨

10. 设置带本地存储功能的排行榜💨

我们先来看看接下来我们要做的效果:🙋🙋🙋

 

有需要源码和素材的同学,在文章末尾有链接。 

下面是另外两个原生JS的游戏和项目,大家可以选择阅读,都有详细解析:

原生JS实现FlappyBird游戏:原生JS实现FlappyBird游戏 超详细解析 快来做一个自己玩吧

原生JS实现本地存储记账本:我用JS做了一个记账本 [数据可本地存储] 附万字详解

1. 案例分析💨

我们先思考一下这个游戏都由哪几个部分或者说哪些功能组成呢?

开始前 :一个开始游戏面板 游戏中:背景滚动  hero的操作  敌机的创建与运动  子弹的创建与运动  碰撞检测游戏结束:一个排行榜面板2. 适配设备 💨

新建一个public.js文件,这个文件放一些我们公共的方法,下面我们先定义一个isPhone方法来判断是否是移动端设备

function isPhone() { var arr = ["iPhone","iPad","Android"]; var is = false; for (var i=0; i<arr.length; i++) { if (navigator.userAgent.includes(arr[i])) { is = true; break; } } return is;}

在isPhone方法里我们定义了一个数组arr用来存储移动端的设备名,UserAgent是HTTP请求中的用户标识,一般发送一个能够代表客户端类型的字符串,includes 方法判断数组是否包含指定的值,包含返回 true,不包含返回 false。

我们默认是PC端,如果includes返回true则代表与数组中的元素匹配,代表是移动端设备,那么我们的isPhone方法就返回true。

这个判断移动端的方法大家可以保存下来,以后很多的项目我们也用的到。 

因为我们规定移动端下背景图片要占满屏幕,所以需要一个if语句进行判断,如果isPhone返回的是true,说明当前在移动端,我们需要修改背景图片的宽高:

sw和sh是在在外面定义的全局变量,默认情况下sw=320,sh=568,因为在后面我们还会用到sw,sh,所以如果设备是移动端的话,需要对它们进行重新赋值:

if (isPhone()) { var bg = document.querySelector('.contain'); sw = document.documentElement.clientWidth + 'px'; sh = document.documentElement.clientHeight + 'px'; bg.style.width = sw; bg.style.height = sh;}

document.documentElement.clientWidth 就是当前设备的屏幕宽度,注意加符号

我们可以在chrome浏览器下模拟移动端不同设备下是否占满全屏,每次换完设备时要刷新页面: 

 

这样的话我们适配设备的效果就完成了,成功做到了可以在移动端下占满全屏,下面就开始制作我们的飞机大战游戏吧!

3. 背景滚动💨

游戏背景是最外层盒子 container 的背景图片,背景图片是在y轴上平铺的,所以我们通过定时器改变背景图片的y轴位置就能达到持续滚动的效果。

我们在实现各个子模块功能的时候都写到单独的文件里,下面我们创建一个背景滚动文件 bg.js ,把相关功能的实现写在这里:

// 背景滚动var dContainer = document.getElementById("container");var dis = 0; //bg滚动的量var speed = 5; //滚动的速度function bgMove() { dis += 5; dis = dis>sh ? 0 : dis; dContainer.style.backgroundPosition = `0 ${dis}px`;}

我们在 index.html 中定义一个定时器,然后每隔30毫秒调用 bgMove 这个方法:

function start() { timer = setInterval(function() { // 2.1 背景滚动 bgMove(); }, 30)}

在我们制作的这个游戏中,不论是背景移动还是待会要做的 hero的移动,敌机的移动,最后封装的函数都需要在这个定时器里调用,这样才会有我们看到的那种动画一样的效果。 

我们看一下背景移动的效果:

这样背景的滚动就完成了,下面我们开始进行 hero 的操作。

4. hero操作💨

我们新建一个控制 hero 移动的 js 文件:hero.js

然后分为三步

1 .获取装hero飞机的盒子

2. 添加键盘事件,判断按下的状态

3. 封装移动函数

这里需要着重强调的就是第二步,我们先看一下代码:(这里37.38.39.40是阿斯克码分别代表左上右下键)

var isLeft = false;var isTop = false;var isRight = false;var isBottom = false;//键盘按下事件window.onkeydown = function(e) { if (e.keyCode === 37) { isLeft = true; } else if (e.keyCode === 38) { isTop = true; } else if (e.keyCode === 39) { isRight = true; } else if (e.keyCode === 40) { isBottom = true; } }//键盘抬起事件window.onkeyup = function(e) { if (e.keyCode === 37) { isLeft = false; } else if (e.keyCode === 38) { isTop = false; } else if (e.keyCode === 39) { isRight = false; } else if (e.keyCode === 40) { isBottom = false; } }

这里每当按下键盘或者键盘抬起的时候,我们都会判断相应的状态,如果没有这一步,我们实现不了飞机向左上飞或者向右上飞,只能要么竖着上下飞,要么横着左右飞。

这里我们再看看hero移动的函数就能更好的理解了:

var dHero = document.getElementById("hero");function heroMove() { var left = dHero.offsetLeft; var top = dHero.offsetTop; if (isLeft) { left -= 8; left = left<-33 ? -33 : left; } if (isTop) { top -= 8; top = top<0? 0 : top; } if (isRight) { left += 8; left = left>sw-33 ? sw-33 : left; } if (isBottom) { top += 8; top = top>sh-82 ? sh-82 : top } dHero.style.left = left + 'px'; dHero.style.top = top + 'px';}

当我们按下左移键时,isLeft等于true,当我们按下上移键时,isTop等于true,所以在移动函数heroMove里,前两个if都会被执行,这样就实现了向左上方飞的效果。

把 hero 的操作函数添加到定时器中:

function start() { timer = setInterval(function() { // 2.1 背景滚动 bgMove(); // 2.2 hero的操作 pc键盘 heroMove(); }, 30) }

下面我们来看一下效果:

 这样我们就实现了通过上下左右键对 hero 的操作

5. 敌机的创建与运动💨原生JS实现飞机大战游戏 超详细解析 快来做一个自己玩吧(原生js实现promise)

在实现敌机的创建之前,因为我们要让生成的敌机实现随机分布,所以需要先写一个随机数函数,我们就在public.js里完成:

function rand(min, max) { return Math.round(Math.random() * (max-min) + min)}

创建一个 enemy.js文件编写敌机的创建与运动,首先我们写一个创建敌机的函数:

var dEnemy = document.getElementById("enemy");function createEnemy() { var d = document.createElement("div"); d.className = "enemy"; d.style.left = rand(0,sw-38) + 'px'; d.speed = rand(3,8); dEnemy.appendChild(d);}

这里我们首先获取 enemy 元素,enemy盒子是作为装载生成敌机的父盒子,类 enemy 就是给创建的 div 盒子增加了敌机的背景,因为最外层的背景盒子我们给了他一个相对定位,然后把装载敌机的盒子一个绝对定位。这样才能让敌机在背景上移动,在类 enemy 里我们定义所有生成的敌机的 top 值都是负的,让敌机从背景外向内移动。然后把创建的div盒子作为 dEnemy 的孩子添加进去。rand函数是创建的一个返回随机数的函数。第三行语句是为了让敌机生成在背景的水平方向的任意位置上,然后让生成的敌机速度也是随机的,减去38是因为我们创建的敌机的宽度是38。

接下来我们看一下敌机的运动函数:

// 敌机的创建于运动var dEnemy = document.getElementById("enemy");//通过概率来限制敌机的创建与游戏难度var diff = 200; //难度系数//敌机运动function enemyMove() { // 1. 敌机的创建 if (rand(0,diff) <= 10) { createEnemy() } // 2. 敌机的运动 var es = dEnemy.children; for (var i=0; i<es.length; i++) { var e = es[i]; if (e.offsetTop > sh) { // 飞出了屏幕,需要删掉 dEnemy.removeChild(e); i --; //防止漏掉元素 continue; } e.style.top = e.offsetTop + e.speed + 'px'; }}

在敌机创建部分我们用了一个if语句,因为我们在通过定时器调用这个函数时,大概每秒钟会调用三十次,那样的话每次调用都创建一个敌机,敌机的数量就太多了。rand(0,200) <= 10意思就是是原来二十分之一的概率,这样生成的敌机数量正好。

还有一个值得注意的点是,当敌机飞出屏幕时,我们需要把敌机这个元素删点,那为什么要i--呢?

比如我们的敌机数组有四个元素,现在判断的是第二个元素,也就是i等于1,当我们移除掉这个元素后,原来的第三个元素就到了我们移除的第二个元素的位置上来。但是因为for循环还会进行一个i++的操作,这样i就等于2了,就是数组的第三个元素。但这其实是第四个元素,因为我们已经把第二个元素删掉了,所以就漏掉了第三个元素,就需要进行一个i--操作来防止漏掉元素。

把 enemyMove 方法添加到主页定时器中:

function start() { timer = setInterval(function() { // 2.1 背景滚动 bgMove(); // 2.2 hero的操作 pc键盘 heroMove(); // 2.3 敌机的创建与运动 enemyMove(); }, 30) }

我们看一下效果:

6. 子弹的创建与运动💨

我们创建一个 bullet.js 文件,子弹的创建和上一节中敌机的创建是很相似的:

function createBullet() { var dHero = document.getElementById("hero"); var d = document.createElement("div"); d.className = "bullet"; d.style.left = dHero.offsetLeft + 33 - 3 + 'px'; d.style.top = dHero.offsetTop + 'px'; dBullet.appendChild(d);}

只不过子弹的定位是跟 hero 相关的,所以子弹的 top,left值需要用到 hero 的位置,' 33 -3 '那里前面介绍过33是指 hero 飞机宽度的一半,而3就是子弹宽度的一半,这样就能保证子弹是从飞机头的那个位置发射出来的。 

接下来我们再完成子弹的运动函数:

//子弹运动及创建var dBullet = document.getElementById("bullet");// 使用间隔var space = 7;var count = 0; //计数//子弹运动function bulletMove() { count ++; // 1. 子弹的创建 if (count === space) { createBullet(); count = 0; } // 2. 子弹的运动 var bs = dBullet.children; for (var i=0; i<bs.length; i++) { var top = bs[i].offsetTop; if (top <= -14) { dBullet.removeChild(bs[i]); i-- ; continue; } bs[i].style.top = top - 9 + 'px'; }}

在子弹的移动函数中我们调用子弹的创建函数,通过 space 和 count 两个变量来控制子弹的生成频率,要不然子弹每隔30毫秒就生成一个就太快了。然后我们让子弹在超出边界后就自动销毁。

我们把这个方法和之前一样加到主页的定时器中:

function start() { timer = setInterval(function() { // 2.1 背景滚动 bgMove(); // 2.2 hero的操作 pc键盘 heroMove(); // 2.3 敌机的创建与运动 enemyMove(); // 2.4 子弹的创建与运动 bulletMove(); }, 30) }

启动项目,看一下子弹的效果:

这样我们子弹的创建与运动就完成了,下一步就该判断子弹命中敌机后,销毁敌机的操作了。

7. 碰撞检测💨

我们在这一节要实现子弹与敌机相碰时,子弹和敌机都会销毁,如果 hero 和敌机相撞那就游戏结束了。首先我们创建一个 check.js 文件,在这里定义上述功能。

下面先理解一下判断是否碰撞的函数:

function isCrash(a,b) { var l1 = a.offsetLeft; var t1 = a.offsetTop; var r1 = l1 + a.offsetWidth; var b1 = t1 + a.offsetHeight; var l2 = b.offsetLeft; var t2 = b.offsetTop; var r2 = l2 + b.offsetWidth; var b2 = t2 + b.offsetHeight; if (r2<l1 || b2<t1 || r1<l2 || b1<t2) { // 不碰撞 return false; } else { // 碰撞 return true; }}

在 if 语句里只要有一个条件不满足就说明不会碰撞,这个很好理解,这里我们就分析一下为什么 r2 < l1 就说明不会碰撞呢? l1 代表飞机到左侧背景的距离, l2 代表敌机到背景左侧的距离,那么 r2 < l1 的意思就是敌机本身的宽度再加上敌机到背景左侧的距离比飞机到背景左侧的距离还小,这样二者肯定不会碰上,所以其他方向同理。 

定义 check 函数判断敌机与hero,敌机与子弹是否碰撞:

function check() { // 1. hero与敌机 // 2. 子弹与敌机 var es = dEnemy.children; var bs = dBullet.children; for(var i=0; i<es.length; i++) { var e = es[i]; // 英雄与敌机 if (isCrash(dHero, e)) { // gameover alert('ganmeover'); clearInterval(timer); } // 子弹与敌机 for (var j=0; j<bs.length; j++) { var b = bs[j]; if (isCrash(e,b)) { // 1. 子弹消失 dBullet.removeChild(b); // 2. 敌机消失 dEnemy.removeChild(e); i --; break; } } }}

在 check 方法中我们调用 isCrash 方法校验英雄与敌机,子弹与敌机是否碰撞,如果英雄与敌机碰撞,我们就清除主页定时器,并执行 gameover 的弹窗。然后通过两个 for 循环,先遍历所有敌机,再对每一个子弹遍历,判断是否子弹和敌机碰撞,如果二者碰撞那就通过 removeChild 把移除元素。

将 check 方法加入定时器中:

function start() { timer = setInterval(function() { // 2.1 背景滚动 bgMove(); // 2.2 hero的操作 pc键盘 heroMove(); // 2.3 敌机的创建与运动 enemyMove(); // 2.4 子弹的创建与运动 bulletMove(); // 2.5 碰撞检测 check(); }, 30)}

运行项目,看一下效果能否都实现:

在子弹在和敌机碰撞时,就达到了消灭敌机的效果,并且 hero 在与敌机相撞时也会弹窗提示游戏结束,这样我们游戏的主体部分就完成了,剩下的就是一个让人头疼的带本地存储功能的计分和排行榜功能了。

8. 统计得分💨

我们设置当子弹击毁敌机的时候得分就加一,得分会在游戏界面的左上角显示出来,这一节我们主要实现得分的这个功能,显示与样式这里先不关注。

因为在子弹和敌机碰撞的时候得分才会加一,所以这个功能应该添加在上一节的 check 方法之中

先在 check.js 中获取元素,定义得分变量 score:

var score = 0; //得分var pScore = document.getElementById("score");

这里 pScore 获取的就是游戏界面左上角装载得分的盒子

然后是得分的逻辑实现:

for (var j=0; j<bs.length; j++) { var b = bs[j]; if (isCrash(e,b)) { // 1. 子弹消失 dBullet.removeChild(b); // 2. 敌机消失 dEnemy.removeChild(e); // 3. 加分 score ++; pScore.innerHTML = "得分:" + score; // 4. 处理数据 i --; break; } }

现在当子弹命中敌机的时候,左上角的得分就会相应的加一。

9. 设置开始与结束界面💨

在游戏开始的时候应该先设置一个开始界面,然后可以输入昵称,这样方便后续结束游戏的时候设置排行榜。

下面是我们定义的开始界面,样式和 html 结构这里就不展示了,我们主要关注功能的实现:

单击开始按钮的时候就会隐藏开始界面,然后调用 start 函数,star函数封装了定时器 timer :

startBut.onclick = function() { if (iptNick.value === "") { alert("昵称不能为空"); return ; } dStart.style.display = 'none'; start(); }

开始界面设置完后,我们就实现结束界面,先看一下结束界面的效果:

在结束界面需要我们把最终得分还有排行榜输出出来,这里我们先不关系排行榜如何设置,先实现游戏结束的功能,当点击再来一次的时候,结束面板就会隐藏,弹出开始面板,因为我们知道结束面板的弹出和 hero 与敌机相撞这个事件是绑定的,所以我们可以把这些功能放在一个 gameover 函数中,当触发事件就调用这个函数。

在 index.html 中我们定义一个 gameover 函数:

//游戏结束function gameover() { //停止计时 clearInterval(timer); //修改本次得分 pShowScore.innerHTML = score; // 设置排行榜 setPHB(); // 显示结束面板 dEnd.style.display = "block"; }

如果游戏结束的话一定要先清除定时器 timer ,否则游戏还会继续进行,然后把最终得分展示在结束面板,然后设置排行榜,这里先定义一个 setPHB 方法,下一节我们再完善里面的功能,最后再显示结束面板,这样 gameover 函数就完成了。

当敌机与hero相撞时,调用gameover函数:

// 英雄与敌机if (isCrash(dHero, e)) { // gameover gameover();}

下面我们实现单击再来一次重新开始游戏的效果

首先肯定是点击它的时候让结束面板隐藏,显示开始面板,我们定义一个 again 方法:

function again() { dEnd.style.display = "none"; dStart.style.display = "block"; }

但是这就完事了么?很明显没有,因为当你每次重新开始游戏的时候都应该让 hero 在起始的中间位置,我们再定义一个 setHeroPosition 方法:

var dHero = document.getElementById("hero");//重新定位hero的位置function setHeroPosition() { dHero.style.left = (sw-66)/2 + 'px'; dHero.style.top = sh - 82 + 'px';}

这个方法我们把它定义在 hero.js 文件中。

那现在重新开始游戏能正常实现了么?也没有,因为我们还得恢复所有数据:

againBut.onclick = function() { again(); //数据还原 dis = 0; count = 0; dBullet.innerHTML = ""; score = 0; pScore.innerHTML = "得分:0"; dEnemy.innerHTML = ""; setHeroPosition(); }

在 index.html 中定义这个点击事件,先调用前面定义过的 again 方法,然后把所有我们计数用的变量初始化,再把画面中的所有子弹和敌机删除,最后调用 setHeroPosition 方法实现 hero 归位。

至此我们开始界面与结束界面的全部功能就都实现了。

 10. 设置带本地存储功能的排行榜💨

我们先想一下这个排行榜应该怎么做,正常就是数据以对象存储在数组里,然后遍历显示在结束面板上。但是这样的话,如果我们刷新页面,所有的数据就被销毁了,那我们这个排行榜也就没有意义了,所以这里要通过 localStorage 本地存储实现。

在 gameover 函数中我们

本文链接地址:https://www.jiuchutong.com/zhishi/296008.html 转载请保留说明!

上一篇:antd:ConfigProvider+getPopupContainer解决筛选框遮挡问题(及其他浮层问题)

下一篇:基于Vue的在线购物系统的设计与实现(论文+源码)_kaic(基于vue的网上商城)

  • 动画效果怎么设置(动画效果怎么设置切入)

    动画效果怎么设置(动画效果怎么设置切入)

  • k30pro支持光学防抖吗(redmi k30pro标准版有没有光学防抖)

    k30pro支持光学防抖吗(redmi k30pro标准版有没有光学防抖)

  • 如何判断华为是否是原装屏(如何判断华为是否是翻新机)

    如何判断华为是否是原装屏(如何判断华为是否是翻新机)

  • 苹果手机摔一下会不会影响使用状况(苹果手机摔一下信号不好了怎么办?)

    苹果手机摔一下会不会影响使用状况(苹果手机摔一下信号不好了怎么办?)

  • 三星手机过热自动关闭程序怎么办(三星手机过热自动关闭那些功能)

    三星手机过热自动关闭程序怎么办(三星手机过热自动关闭那些功能)

  • 淘宝相册权限设置在哪(淘宝相册权限设置好了怎么还是不行)

    淘宝相册权限设置在哪(淘宝相册权限设置好了怎么还是不行)

  • 腾讯课堂放视频没声音(腾讯课堂放视频声音很小)

    腾讯课堂放视频没声音(腾讯课堂放视频声音很小)

  • 迅雷卸载了下载的视频还在吗(迅雷卸载下载一半的文件去哪了)

    迅雷卸载了下载的视频还在吗(迅雷卸载下载一半的文件去哪了)

  • pad版钉钉可以共享屏幕嘛(钉钉在平板上可以共享屏幕吗)

    pad版钉钉可以共享屏幕嘛(钉钉在平板上可以共享屏幕吗)

  • 小米10pro是双卡双待吗(小米10pro双卡都支持5g吗)

    小米10pro是双卡双待吗(小米10pro双卡都支持5g吗)

  • iphone怎么拦截垃圾短信(iphone 如何拦截)

    iphone怎么拦截垃圾短信(iphone 如何拦截)

  • 荣耀20怎么没有返回键(荣耀20怎么没有电池最大容量)

    荣耀20怎么没有返回键(荣耀20怎么没有电池最大容量)

  • deebot扫地机器人充电亮红灯还滴滴响(deebot扫地机器人怎么连接wifi)

    deebot扫地机器人充电亮红灯还滴滴响(deebot扫地机器人怎么连接wifi)

  • 快手播放次数怎么算(快手播放次数怎么打开)

    快手播放次数怎么算(快手播放次数怎么打开)

  • 手机短信字体大小怎么设置(手机短信字体大小在哪里调节)

    手机短信字体大小怎么设置(手机短信字体大小在哪里调节)

  • 拼多多卸载不掉(拼多多卸载不掉只能移除)

    拼多多卸载不掉(拼多多卸载不掉只能移除)

  • 淘宝申请试用还要退回去吗(淘宝申请试用是什么意思)

    淘宝申请试用还要退回去吗(淘宝申请试用是什么意思)

  • 搜不到路由器wifi(搜不到路由器的信号怎么回事)

    搜不到路由器wifi(搜不到路由器的信号怎么回事)

  • iphone不显示4g显示lte(苹果手机不显示4g怎么回事?)

    iphone不显示4g显示lte(苹果手机不显示4g怎么回事?)

  • 手机开发者选项在哪(手机开发者选项怎么设置)

    手机开发者选项在哪(手机开发者选项怎么设置)

  • 共享热点怎么连接(共享热点怎么连接不上什么原因)

    共享热点怎么连接(共享热点怎么连接不上什么原因)

  • 手机qq来消息怎么没声音(手机qq消息怎么不和电脑同步)

    手机qq来消息怎么没声音(手机qq消息怎么不和电脑同步)

  • 苹果摄像头是索尼的吗(苹果摄像头是索尼镜头吗)

    苹果摄像头是索尼的吗(苹果摄像头是索尼镜头吗)

  • 计算机属性在哪里(计算机属性在哪里win7)

    计算机属性在哪里(计算机属性在哪里win7)

  • 写微博是在什么位置写(写微博的地方在哪)

    写微博是在什么位置写(写微博的地方在哪)

  • 企业所得税核定征收的条件
  • 小规模免收增值税 其他收益怎么算
  • 应纳税所得额的会计分录
  • 企业所得税必须计提吗?什么时候计提?
  • 进料加工手册核销是什么意思
  • 外贸企业申报出口退税时的会计分录
  • 编制利润表会计等式
  • 计提劳务成本月末需要结转吗
  • 确认应收账款不确认收入
  • 发票认证后1年还能用吗
  • 购买方和销售方一样可以报销吗
  • 代销方式的特点
  • 清算所得计算例题
  • 蔬菜免税会计分录怎么做
  • 软件行业服务费印花税
  • 企业存货跌价准备一经计提在以后会计期间不得转回
  • 企业空气检测费应该计入什么会计科目核算?
  • 计提职工教育经费计入什么科目
  • 当企业预收款项无需退回
  • win10任务栏不显示最近
  • 个人独资企业没有章程
  • 租赁合同维修义务谁承担
  • 进价销售交增值税吗
  • 代销商品手续费计入什么科目
  • 权益净利率是什么意思啊
  • linux zen3
  • BIOS里没有USB-HDD选项
  • 应纳消费税包不包括代收代缴
  • 在windows7操作具有
  • 转账支票出账日期
  • 加权平均数的代码
  • 公司购置办公楼自用
  • 生产型企业出口外购货物可以退税吗
  • 含工资表的会计科目
  • vue引用svg矢量图
  • 非高新企业自主研发,相关政策
  • 资产总额怎么计算公式
  • php判断ua
  • mysqldump命令不存在
  • 工程施工资产负债表存货计算公式
  • 工厂院里栽什么树好呢
  • 外贸企业收款有限额吗
  • 出口商品没有发票可以入收入吗
  • ❤️国庆假期快到了,用python写个倒计时程序,助你熬到假期!❤️
  • 现金流量表怎么填写
  • 代宰 增值税
  • 个体工商户怎么年报
  • mysql 自动断开
  • 市政绿化工程的施工方案
  • 没有发票的运输费用怎么入账
  • 小微企业免税销售额是多少2023年
  • 小规模纳税人征税起点
  • 专项应付款和政府补助的区别
  • 冲暂估的账务处理
  • 安全生产费相关规定
  • 分配股利需要缴纳个税吗
  • 缴纳社保记账凭证怎么开
  • 工程招标费用由谁支付
  • 如何提取坏账准备
  • 在建工程的进项税额不再分2年抵扣
  • 贴现办理流程
  • sql hash
  • mysql常用功能
  • sql server复制表数据
  • windows2000开机视频
  • 重庆四日游最佳攻略超详细
  • u盘如何安装win7系统
  • windows升级后c盘满了
  • linux用户管理器在哪
  • xp系统咋样
  • win7系统无线网络
  • 随机游戏插件怎么使用
  • unity3d脚本参考手册
  • 最简单手电筒
  • 基于js实现微信直播
  • 饮料开专票几个点
  • 纳税申报表如何打印
  • 工会经费扣除标准2022
  • 税务异地协查系统管理办法
  • 税务部门立足
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设