vue项目中,前端与后台进行数据请求或者提交的时候,如果后台没有设置跨域,前端本地调试代码的时候就会报“No 'Access-Control-Allow-Origin' header is present on the requested resource.” 这种跨域错误。
要想本地正常的调试,解决的办法有三个:
一、后台更改header
header('Access-Control-Allow-Origin:*');//允许所有来源访问
header('Access-Control-Allow-Method:POST,GET');//允许访问的方式
这样就可以跨域请求数据了
二、使用JQuery提供的jsonp (注:vue中引入jquery,自行百度)
methods: {
getData () {
var self = this
$.ajax({
url: 'http://f.apiplus.cn/bj11x5.json',
type: 'GET',
dataType: 'JSONP',
success: function (res) {
self.data = res.data.slice(0, 3)
self.opencode = res.data[0].opencode.split(',')
}
})
}
}
通过这种方法也可以解决跨域的问题。
三、使用http-proxy-middleware 代理解决(项目使用vue-cli脚手架搭建)
例如请求的url:“/business/remind/user”
1、打开vue.config.js.js,在proxy中添写如下代码:
// 运行配置
devServer: {
port: '9527', //代理端口
open: false, //项目启动时是否自动打开浏览器,我这里设置为false,不打开,true表示打开
proxy: {
'/api': {
target: process.env.VUE_APP_HTTP_URL,
changeOrigin: true, //是否跨域
pathRewrite: { //重写路径
'^/api': '/' // 或 者 'http://localhost:8080/api'
}
// 既然我们设置了代理,则所有请求url都已写成/api/xxx/xxx,那请求如何知道我们到底请求的是哪个服务器的数据呢
// 因此这里的意义在于, 以 /api开头的url请求,代理都会知道实际上应该请求那里,
// ‘我是服务器/api’,后面的/api根据实际请求地址决定,即我的请求url:/api/test/test,被代理后请求的则是
// https://我是服务器/api/test/test
}
}
},
附带vue.config.js下的代码
const chalk = require('chalk')
const path = require('path');
function resolve (dir) {
return path.join(__dirname, dir)
}
module.exports = {
// 没有书写outputDir属性 默认'dist' 对应dev.assetsSubDirectory
outputDir: 'dist',
// https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only
// compiler: false,
//在vue-cli.3.3版本后 baseUrl被废除了,因此这边要写成 publicPath ( 资源地址 )
publicPath: process.env.NODE_ENV === 'production' ? process.env.VUE_APP_PUBLICPATH : '/' ,
// css相关配置
css: {
// 是否使用css分离插件 ExtractTextPlugin
extract: true,
// 开启 CSS source maps?
sourceMap: false,
// css预设器配置项
loaderOptions: {}
// 启用 CSS modules for all css / pre-processor files.
// modules: false
},
// 运行配置
devServer: {
port: '8222', //代理端口
open: false, //项目启动时是否自动打开浏览器,我这里设置为false,不打开,true表示打开
proxy: {
'/api': {
target: process.env.VUE_APP_HTTP_URL,
changeOrigin: true, //是否跨域
pathRewrite: { //重写路径
'^/api': '/' // 或 者 'http://localhost:8080/api'
}
// 既然我们设置了代理,则所有请求url都已写成/api/xxx/xxx,那请求如何知道我们到底请求的是哪个服务器的数据呢
// 因此这里的意义在于, 以 /api开头的url请求,代理都会知道实际上应该请求那里,
// ‘我是服务器/api’,后面的/api根据实际请求地址决定,即我的请求url:/api/test/test,被代理后请求的则是
// https://我是服务器/api/test/test
}
}
},
chainWebpack: config => {
// 提示输出的哪个地址
console.log(chalk.blueBright('\n\n running ' + process.env.VUE_APP_PROJ_NAME + ' : ') +
chalk.yellowBright(process.env.VUE_APP_HTTP_URL + ' please wait... \n'));
// 判断不同环境 做相应处理
if(process.env.NODE_ENV === 'production') {
// 测试生产环境, 不压缩js代码
if (process.env.VUE_APP_TITLE === 'alpha') {
config.optimization.minimize(false)
}
}
//set第一个参数:设置的别名,第二个参数:设置的路径
config.resolve.alias
.set('@',resolve('./src'))
.set('components',resolve('./src/components'))
.set('assets',resolve('./src/assets'))
.set('views',resolve('./src/views'))
.set('network',resolve('./src/network'))
//注意 store 和 router 没必要配置
config.plugin('html')
.tap(args => {
args[0].title = '公募综合业务平台'
return args
})
}
}
蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请加微信ban_lanlan,报下信息,蓝小助会请您入群。欢迎您加入噢~~
希望得到建议咨询、商务合作,也请与我们联系01063334945。
分享此文一切功德,皆悉回向给文章原作者及众读者. 免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司。
我使用命令 npm run dev 启动项目 报了下面的错。
'webpack-dev-server' 不是内部或外部命令,也不是可运行的程序
> webpack-dev-server --inline --progress --config build/webpack.dev.conf.js
'webpack-dev-server' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! vue@1.0.0 dev: `webpack-dev-server --inline --progress --config build/webpack.dev.conf.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the vue@1.0.0 dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm WARN Local package.json exists, but node_modules missing, did you mean to install?npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\lara\AppData\Roaming\npm-cache\_logs\2018-06-12T09_40_42_892Z-debug.log
什么环境都是好的,刚使用npm run dev 启动了一个前端项目都是好的,但是现在这个项目就不行了。
删除项目的node_modules文件夹(当前运行的项目中没有node_modules 文件夹的直接运行第二步)
在项目目录里运行 npm install 命令

在项目目录里运行npm run build 命令
在项目目录里运行npm run dev 命令
这样我就可以成功运行项目了。
1.区别:vuex存储在内存,localstorage(本地存储)则以文件的方式存储在本地,永久保存(不主动删除,则一直存在);sessionstorage( 会话存储 ) ,临时保存。localStorage和sessionStorage只能存储字符串类型,对于复杂的对象可以使用ECMAScript提供的JSON对象的stringify和parse来处理
2.应用场景:vuex用于组件之间的传值,localstorage,sessionstorage则主要用于不同页面之间的传值。
3.永久性:当刷新页面(这里的刷新页面指的是 --> F5刷新,属于清除内存了)时vuex存储的值会丢失,sessionstorage页面关闭后就清除掉了,localstorage不会。
注:大家可能觉得用localstorage可以代替vuex, 对于不变的数据确实可以,但是当两个组件共用一个数据源(对象或数组)时,如果其中一个组件改变了该数据源,希望另一个组件响应该变化时,localstorage,sessionstorage无法做到,原因就是区别1。
vuex是存储在页面上的变量,说到底还是个Object,刷新页面就清空了。而storage是存储在浏览器的,和页面就无关了,刷新页面也不会清空
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
我们经常会将Word转换成PDF,下面给大家介绍一种很不错的Word转PDF格式的方式。
打开浏览器搜索speedpdf找到并打开在线转换工具首页,选择主页上的Word转PDF进入转换(也可以点击上方所有工具字样,选择Word转PDF进入)。
将需要转换的Word文档添加上传后,点击进度条后面的转换按钮,就可以开始转换了,等待转换完成后点击下载箭头即可。
如果转换前有登录账户,还可以通过点击登录头像处,选择账户,在转换记录中查看转换状态和下载转换后的文档。
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
目录
确保我们在vue中实现页面跳转到我们所想的页面
可以看到当我们点击不同的组件的时候我们实现了路由的功能:在vue中实现页面的跳转
注意看,当我点击的时候上面地址栏中加载了不同的网页。下面我们来学习下路由的写法
路由书写写法:
在index.js中的router对象中书写
-
const router = new VueRouter({
-
mode: 'history',//默认是hash模式
-
})
hash模式:
history模式:
两种模式的区别:
起步 | Vue RouterVue Router3官网介绍: 起步 | Vue Router
- 下载与导入vue-router
- 导入组件
- 创建routes路由规则(路径和页面一一对应)
- 创建路由对象
- 把路由对象挂载到App.vue
- 在页面写路由导航router-link (生成a标签)
- 在页面写路由出口router-view (生成占位盒子,用于显示页面内容)
下面开始我们相关文件的创建
1.创建我们的脚手架(此时没有选择Router):
2.准备我们的App.vue文件:
-
<template>
-
<div>
-
<!-- 顶部导航栏 -->
-
<div class="footer_wrap">
-
<a href="#/find">发现音乐</a>
-
<a href="#/my">我的音乐</a>
-
<a href="#/friend">朋友</a>
-
</div>
-
<!-- 下面内容 -->
-
<div class="top"></div>
-
</div>
-
</template>
-
-
<script>
-
export default {
-
methods: {}
-
}
-
</script>
-
-
<style scoped>
-
body,
-
html {
-
margin: 0;
-
padding: 0;
-
}
-
.footer_wrap {
-
position: fixed;
-
left: 0;
-
top: 0;
-
display: flex;
-
width: 100%;
-
text-align: center;
-
background-color: #333;
-
color: #ccc;
-
}
-
.footer_wrap a,
-
span {
-
cursor: pointer;
-
flex: 1;
-
text-decoration: none;
-
padding: 20px 0;
-
line-height: 20px;
-
background-color: #333;
-
color: #ccc;
-
border: 1px solid black;
-
}
-
.footer_wrap a:hover,
-
span:hover {
-
background-color: #555;
-
}
-
-
.top {
-
padding-top: 62px;
-
}
-
-
.footer_wrap .router-link-active {
-
background-color: #000;
-
}
-
</style>
3.在src下面新建views文件夹并创建我们需要的.vue文件
3.1 find.vue
-
<template>
-
<div>
-
<div class="nav_main">
-
<router-link to="/Ranking">排行</router-link>
-
<router-link to="/Recommend">推荐</router-link>
-
<router-link to="/SongList">歌单</router-link>
-
</div>
-
-
<div style="1px solid red;">
-
<router-view></router-view>
-
</div>
-
</div>
-
</template>
-
-
<script>
-
export default {
-
name: 'find',
-
}
-
</script>
-
-
<style scoped>
-
.nav_main {
-
background-color: red;
-
color: white;
-
padding: 10px 0;
-
}
-
.nav_main a {
-
text-align: center;
-
text-decoration: none;
-
color: white;
-
font-size: 12px;
-
margin: 7px 17px 0;
-
padding: 0px 15px 2px 15px;
-
height: 20px;
-
display: inline-block;
-
line-height: 20px;
-
border-radius: 20px;
-
}
-
.nav_main a:hover {
-
background-color: brown;
-
}
-
.nav_main .router-link-active{
-
background-color: brown;
-
}
-
</style>
3.2 my.vue
-
<template>
-
<div>
-
<img src="../assets/my.png" alt="" width="100%">
-
</div>
-
</template>
-
-
<script>
-
export default {
-
name: 'my',
-
};
-
</script>
-
-
<style scoped>
-
-
</style>
3.3 friend.vue
-
<template>
-
<div>
-
<ul>
-
<li>这是当前页面 query 接收到的参数:
-
<span>姓名:{{ $route.query.name }}</span> --
-
<span>年龄:{{$route.query.age}}</span>
-
</li>
-
<li>这是当前页面 params 接收到的参数:
-
<!-- <span>姓名:{{ $route.params.name }}</span> --
-
<span>年龄:{{ $route.params.age }}</span> -->
-
</li>
-
</ul>
-
</div>
-
</template>
-
-
<script>
-
export default {
-
name: 'friend',
-
};
-
</script>
-
-
<style scoped>
-
-
</style>
3.4 notfound.vue
-
<template>
-
<div class="box">
-
<h1>这是一个 404 页面</h1>
-
<img src="../assets/404.png" alt="">
-
</div>
-
</template>
-
-
<script>
-
export default {
-
name: 'notfound',
-
data() {
-
return {
-
-
};
-
},
-
-
};
-
</script>
-
-
<style scoped>
-
.box {
-
display: flex;
-
flex-direction: column;
-
justify-content: center;
-
align-items: center;
-
}
-
</style>
4.准备图片素材(所有素材可私信博主获取)
5.所有准备工作做完现在开始我们的文件配置
1.下载与导入vue-router
npm i vue-router@3.6.5
导入vue-router (在main.js中)
-
//main.js中导入
-
// 0.导入路由
-
import VueRouter from 'vue-router'
-
// 使用vue的插件,都需要调用Vue.use()
-
Vue.use(VueRouter)
2.导入组件
@符号代表 /src 文件夹的绝对路径,在脚手架中文件比较多的时候,使用这个@符号会更加的方便
在main.js中导入
-
// 导入组件
-
import find from '@/views/find.vue'
-
import friend from '@/views/friend.vue'
-
import my from '@/views/my.vue'
-
import notfound from '@/views/notfound.vue'
3.创建路由规则
路由规则作用: 设置 url 和 组件 对应的规则
在main.js中写入
-
// 路由规则
-
const routes = [
-
{ path: '/find', component: find },
-
{ path: '/friend', name: 'friend', component: friend },
-
{ path: '/my', component: my },
-
{ path: '/notfound', component: notfound },
-
]
4.创建路由对象
路由对象: 帮你管理这些路由规则
在main.js中写入
-
// 创建路由对象
-
const router = new VueRouter({
-
routes// (缩写) 相当于 routes: routes
-
})
5.挂载路由到根组件
挂载到根组件作用:让你的整个应用都有路由功能
在main.js中写入
-
// 挂载路由到根组件
-
new Vue({
-
router,
-
render: h => h(App)
-
}).$mount('#app')
6.在页面写路由导航router-link
作用与a标签一样实现跳转,好处:当点击链接的时候自带一个专属类名
在App.vue中我们将传统的a标签进行替换:
替换a标签原因:便于我们做专属效果
我们选中点击的超链接做触发效果:
7在页面写路由出口router-view
占位盒子,用于渲染路由匹配到的组件
(<router-view> : 是vue内置的一个组件,会自动替换成路由匹配的组件 )
好了一个最最最基本的路由就被我们制作完成啦!下面我们来看看效果:
上述的操作有些许麻烦,下面我们来使用我们开发中常用的自动配置方法
创建脚手架方式与手动配置类似,唯一不同是此处必须选择Router
对比手动模式:
此刻:脚手架已经帮我们创建好了Router路由不需要我们下载与导入vue-router了
只需要写:
- 导入组件
- 配置路由规则
- 路由导航
- 路由出口
并且为了进一步的封装我们的配置信息,我们的配置代码将写在router/index.js下,不再是全部写在main.js下。
1.导入组件(index.js中)
-
import find from '@/views/find.vue'
-
import friend from '@/views/friend.vue'
-
import my from '@/views/my.vue'
-
import notfound from '@/views/notfound.vue'
2.配置路由规则(index.js中)
-
{ path: '/find', component: find },
-
{ path: '/friend', name: 'friend', component: friend },
-
{ path: '/my', component: my },
-
{ path: '/notfound', component: notfound }
3.路由导航(直接cv我们之前的App.vue文件)
-
<router-link to="/find">发现音乐</router-link>
-
<router-link to="/my">我的音乐</router-link>
-
<router-link to="/friend">朋友</router-link>
4.路由出口(App.vue中)
-
<div class="top">
-
<router-view></router-view>
-
</div>
效果查看:
自动配置省去了一些固定不变的操作,我们不需要写繁琐且固定的代码,只需要写不同的代码。且代码书写的位置都给我们设置好了,我们直接遵守该规范书写代码即可
路由重定向官方文档:重定向和别名 | Vue Router
重定向应用场景: 页面输入根路径/ , 自动跳转到首页
注意点: 重定向只是修改路径, 还需要单独去设置路由匹配规则
重定向命令:
-
{
-
path: '/',
-
/*
-
(1)重定向只是修改页面路径。 输入 / 会重定向到 /路径
-
(2)只有component才会让vue去寻找路由匹配页面。所以设置了重定向,还需要单独设置匹配规则
-
*/
-
redirect: "路径"
-
},
1. 就拿我们刚才创建的举例:

实现效果:当我在浏览器中打开的时候我没有输入任何路径,vue自动帮我们跳转到了 my.vue这个页面组件
2.也可以利用重定向来设置当我们路径错误提示404页面:
实现效果:当我任意输入没有匹配的路径,自动帮我们跳转到了notfound.vue这个组件
实现页面中存在第二级的跳转
写法(拿我们上述的案例实操,需要素材可私信博主喔):
①在index.js中引入
-
// 导入二级路由
-
import Ranking from '@/views/second/Ranking.vue'
-
import Recommend from '@/views/second/Recommend.vue'
-
import SongList from '@/views/second/SongList.vue'
②在需要引用的组件中使用:
-
//格式:
-
{
-
path: '路径', component: 组件名, children: [
-
//此处填写二级路由的路径信息
-
]
-
}
-
{
-
path: '/find', component: find, children: [
-
{path:'/',redirect:'/SongList'},
-
{ path: '/Ranking', component: Ranking },
-
{ path: '/Recommend', component: Recommend },
-
{ path: '/SongList', component: SongList }
-
]
-
}
③写路由导航与出口
查看效果:
可以看到:当我们点击一级路由之后,我们还可以点击二级路由到我们的专属页面中
有两种跳转传参方式:
- 声明式导航
- 编程式导航
①query写法:
在路径中加参数信息即可
<router-link to="/路径?参数名=参数值&参数名=参数值</router-link>
接收信息:
在触发的组件中书写{{ $route.query.属性名}}接收
举个例子:
②params写法:
在index.jsx文件中写:参数名。在需要传递的路由路径中写参数值
接收信息:
在触发的组件中书写{{ $route.params.属性名}}接收
实现效果:
①query写法:
结构:
-
this.$router.push({
-
path: '/路径',
-
query: { 属性名: '属性值'}
-
})
接收信息:
在触发的组件中书写{{ $route.query.属性名}}接收
举个例子:
②params写法
结构:
-
this.$router.push({
-
name: '我们注册路径的组件名',//写path获取不到值!!!
-
query: { 属性名: '属性值'}
-
})
注意点:写path获取不到值,需要用name
接收信息:
在触发的组件中书写{{ $route.params.属性名}}接收
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
目录
上部分为标题、中间为表单、底部为确定按钮
底部背景、标题文本、右上角关闭按钮
祝福语文本、红包数量文本、红包总金额、当前余额文本显示、以及前往充值按钮
左边为需支付金额显示,右边为取消和确定按钮
图片宽度380px像素,高度56px像素
2)背景图片自动填充
布局一个div,宽度为400px像素,高度为56px像素,然后再设置背景图片样式,由于图片本身宽度小于div宽度,div会多出20px像素,图片会自动填充,默认效果如下
-
<div style="width:400px;height:56px;background:url(/1674461966454.jpg);background-size: 100%;">
-
-
</div>
3)图片百分比显示
再给div设置背景百分比缩放显示,效果如下
background-size: 100%;
4)文本
布局一个span标签,显示"添加红包"文本,白色黑体,18号字体,加粗,左对齐,且左边距20px像素。并设置div标签56px像素垂直居中样式,效果如下
5)关闭按钮
在右上角添加一个关闭按钮,一般可以设置一个svg标签图标,设置高28px,宽36px
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAAA4CAYAAABez76GAAAAAXNSR0IArs4c6QAAAtVJREFUeF7tm2FO3DAQhR+0BVZt2QIFujfrQXqMHqQ3W4kflRYJrZBArV6EUTa7jj0ee0yILUUIZcb2fJnMsx3tEYAfAI4x3/YPwDOARwAPAJ76KI4AfAdwMl8+e5ET0j0AggMBXQBYNEA7BJhNfwmJgL6+XI3RLgFm0oaAmD3Motb2CdwREOsP61Br+wQeCIgKRiVrbZ/AEwGxzV3qfcnRFWm2JvUeRA5Qk/oAoCb1AUBN6gOAmtQHADWpDwBqUh8BqEn9AUhO5nmrSX0AkLnULxaL7gFtt9vu7EXatP4x4/UzyFTqGdx6vf7NSa5Wq19SSFr/GDi06QMyk3oX3HK5/MlJbDabPxJIWv9YOENAZlI/DFACSeMrAeNs+xlkKvUpgab4pEDp+wwBmUq9JGCJrRbKGCBzqY8JPMYmJ5QxQOZSz8mMAeB9qp0r6JJ6lQPa8BUzlfp+AD5ItKkFZ6hi/N9M6g893UOQ+nbS5UCJDDKTet/kfZBqwDmUQaZSL8mitwToCsBpjvSU9jGFV4wxnQP4Ig1Oaz+VIt2prvWn6CnJPAGZFuqYRWCMjTaDff7DdZCzM9lySAKX2OaE5QPEGsRaVKylBJziow3AB4iv2e3gvEg71qu/JlCNb0oAPkDdCh/A55ROQz7aAy+tf2h+/ftjgD4CuJF0JrHVHplq/WPnOgaIfVwCOIvtTGqnPXTX+sfMNwSo6uY1JoDSNiFARWtR6eBy9B8DiDbXAFiTZtdiABHKbF+1WECEVGUTWztlJYBoS1WrchRSC5QEEOdIe54Xzea3HVJAs4OUAoiQuFdjJn2qlfpW46YCcpC+lVxpW0EYG0cDyPXLDS0VLkdfb4HJzhxyBcVFJBXu3S0mcwFyxZufrplROfutmlUlAmEBJyRek/8tbAlA7om/C1AlATlQHIMLS35O4tnSpLLKAtCwhrCQExj/8vrwAo3gasxntMb9B9PXrmqWhf+yAAAAAElFTkSuQmCC
设置相对定位position样式,位于右上角。它所在的父级就要设置绝对定位relative。这样关闭按钮图标就会以它所在的父级定位,否则可能会布局错位,比如下面错位效果
-
<style type="text/css">
-
.title { width: 400px; height: 56px; background: url(/1674461966454.jpg); background-size: 100%; line-height: 56px;position:relative; }
-
.title-text { font-size: 18px; font-weight: bold; color: #fff; font-family: 黑体; margin-left: 20px; }
-
.close { position: absolute; top: 0px; right: 0px; width: 36px; height: 28px; }
-
</style>
-
-
<div class="title">
-
<span class="title-text">添加红包</span>
-
<img class="close" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAAA4CAYAAABez76GAAAAAXNSR0IArs4c6QAAAtVJREFUeF7tm2FO3DAQhR+0BVZt2QIFujfrQXqMHqQ3W4kflRYJrZBArV6EUTa7jj0ee0yILUUIZcb2fJnMsx3tEYAfAI4x3/YPwDOARwAPAJ76KI4AfAdwMl8+e5ET0j0AggMBXQBYNEA7BJhNfwmJgL6+XI3RLgFm0oaAmD3Motb2CdwREOsP61Br+wQeCIgKRiVrbZ/AEwGxzV3qfcnRFWm2JvUeRA5Qk/oAoCb1AUBN6gOAmtQHADWpDwBqUh8BqEn9AUhO5nmrSX0AkLnULxaL7gFtt9vu7EXatP4x4/UzyFTqGdx6vf7NSa5Wq19SSFr/GDi06QMyk3oX3HK5/MlJbDabPxJIWv9YOENAZlI/DFACSeMrAeNs+xlkKvUpgab4pEDp+wwBmUq9JGCJrRbKGCBzqY8JPMYmJ5QxQOZSz8mMAeB9qp0r6JJ6lQPa8BUzlfp+AD5ItKkFZ6hi/N9M6g893UOQ+nbS5UCJDDKTet/kfZBqwDmUQaZSL8mitwToCsBpjvSU9jGFV4wxnQP4Ig1Oaz+VIt2prvWn6CnJPAGZFuqYRWCMjTaDff7DdZCzM9lySAKX2OaE5QPEGsRaVKylBJziow3AB4iv2e3gvEg71qu/JlCNb0oAPkDdCh/A55ROQz7aAy+tf2h+/ftjgD4CuJF0JrHVHplq/WPnOgaIfVwCOIvtTGqnPXTX+sfMNwSo6uY1JoDSNiFARWtR6eBy9B8DiDbXAFiTZtdiABHKbF+1WECEVGUTWztlJYBoS1WrchRSC5QEEOdIe54Xzea3HVJAs4OUAoiQuFdjJn2qlfpW46YCcpC+lVxpW0EYG0cDyPXLDS0VLkdfb4HJzhxyBcVFJBXu3S0mcwFyxZufrplROfutmlUlAmEBJyRek/8tbAlA7om/C1AlATlQHIMLS35O4tnSpLLKAtCwhrCQExj/8vrwAo3gasxntMb9B9PXrmqWhf+yAAAAAElFTkSuQmCC" alt="">
-
</div>
1)组成元素
红色星号、文本、输入文本框、刷新文本按钮
2)calc函数
它属于css3的功能,calc() 函数用于动态计算长度值。对于布局非常有作用。
需要特别注意,函数内的参数值前后都需要保留一个空格,例如:width: calc(100% - 40px);
3)刷新小图标
样式设置16x16高宽度
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAA3NJREFUSEu1lX+IVFUUx7/nPpV1N1zbzNQsXFkUoZBCqH+KNhJikKid14QpsjLv3Uc/yCQpCcISot+yJZHz3qxj2xIxzozJYCCuWiREfxQZJIT9IgjKoq0l3WZ33v3GvN3ZdczdmWXr/vfePef7uefce84R/M9LGtVPFYvN+Lm0H8SVIhwi5BcFc7i1FScSiUQ4lU7DgN7e3MpyyLMAVK2YnBOoXVp37bscJAKk3i0uwvnRByFsmjQKv/KcxJGLnVJvZ69XI1hNkasAWUXCAXldxUYgAy0tTYlNmzYMXuwzBgjyu0HzzCUnMPObrKVbtnSdmyr8bDZrDQ7hAaHsJdEmIh8vv7Z5fSwWK1V9IkAQ5JeTdAEsJrAZ4BWRwbw5HV73fd/Wu6dM5tCKkdHwJMAVEHnTc+1HawCVj76+oy3DpaHPQKwG5ALA5kYBFf90unBDaMLPRaAEcrPr2l+OpW58pYL8E6B5FcAZAPMBtM8EUJHx/dwegtsF6j2t4xsnAJnMyaaR8m/fg1giFmI0shPELVhorvESiT/rpai6H6Ua5gdSypYyyxwn8XsUgd+bu4shjwH4Ubt2+4ED7y8wJmxLJu3vGhWv2vnBweMk7lSCe133/sNjAL/wFBG+CJE3PNfeNlPRmqcc5J8HzdMQ9Zznxp+tPtMANI4oeVw79uuzAfjp3DYa9kBUj+fGt49HMHE5j2kd3zsbQCqdfxLGvARRr3lufEdNikRkn3bth2YFCPL7QbMVIg97rv3WeKEV1hiGZ0Tw68JWLp2ueU0HJ6n8dO6nymtUImsrtTBZB37uC4BrxZL1OmkPNBpFJpNdMlpWAxTpEeEgQ+YAOetpe9UlhZbbCfIFERxzHftuETGNQHz/4AYCRVHqCMiVJNcILK11V1AD6OsrLB4uhaejYlOySzv27hkBRL4h2QHB17ip/UZv3brRGsBYP8nfHhoeB6hEsVs7iXfqQSYiEERDh2KSmDPvVLVJ/mvg+OnCDprwlYgucpRzrUem66hBkIsZsmZuVHwtJfc4jl287EQLgkObifIeElcDUoLgFCAfKZgPOzoWfdLZ2VmuRtbf/8GC88MX+gVcVv1HyB+Ya3mVg005MtPpbJuhehlgNwlrMlXyqaftW+ulrrpfdyZHJ/z7r9tAq1Ng7gDltNZ28j8DNCo0ld0/bOx/KATgarIAAAAASUVORK5CYII=
4)文本框默认高亮
input输入文本框默认点击选中会有一个高亮的效果,可以设置样式去掉
outline:none;
5)随机文本
设置随机祝福语文本值,可设置js全局数组参数变量保存。
并且给右边的刷新按钮绑定点击事件,然后在事件内使用随机函数进行随机显示
-
<script type="text/javascript">
-
$(function () {
-
-
// 祝福语
-
var labelText = ['成就一亿技术人!', '节日快乐', 'Hello World', '新春大吉!', '大吉大利', 'Bug Free'];
-
$('.cl-input img').click(function () {
-
// Math.random() - 随机函数会产生0~1之间的值
-
var index = parseInt(Math.random() * labelText.length);
-
var text = labelText[index];
-
$('.cl-input input').val(text);
-
});
-
});
-
</script>
-
<div class="content-label">
-
<div class="cl-text">
-
<span style="color:#f00;">*</span>
-
<span>祝福语</span>
-
</div>
-
<div class="cl-input">
-
<input placeholder="请填写红包祝福语或标题" value="成就一亿技术人!" />
-
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAA3NJREFUSEu1lX+IVFUUx7/nPpV1N1zbzNQsXFkUoZBCqH+KNhJikKid14QpsjLv3Uc/yCQpCcISot+yJZHz3qxj2xIxzozJYCCuWiREfxQZJIT9IgjKoq0l3WZ33v3GvN3ZdczdmWXr/vfePef7uefce84R/M9LGtVPFYvN+Lm0H8SVIhwi5BcFc7i1FScSiUQ4lU7DgN7e3MpyyLMAVK2YnBOoXVp37bscJAKk3i0uwvnRByFsmjQKv/KcxJGLnVJvZ69XI1hNkasAWUXCAXldxUYgAy0tTYlNmzYMXuwzBgjyu0HzzCUnMPObrKVbtnSdmyr8bDZrDQ7hAaHsJdEmIh8vv7Z5fSwWK1V9IkAQ5JeTdAEsJrAZ4BWRwbw5HV73fd/Wu6dM5tCKkdHwJMAVEHnTc+1HawCVj76+oy3DpaHPQKwG5ALA5kYBFf90unBDaMLPRaAEcrPr2l+OpW58pYL8E6B5FcAZAPMBtM8EUJHx/dwegtsF6j2t4xsnAJnMyaaR8m/fg1giFmI0shPELVhorvESiT/rpai6H6Ua5gdSypYyyxwn8XsUgd+bu4shjwH4Ubt2+4ED7y8wJmxLJu3vGhWv2vnBweMk7lSCe133/sNjAL/wFBG+CJE3PNfeNlPRmqcc5J8HzdMQ9Zznxp+tPtMANI4oeVw79uuzAfjp3DYa9kBUj+fGt49HMHE5j2kd3zsbQCqdfxLGvARRr3lufEdNikRkn3bth2YFCPL7QbMVIg97rv3WeKEV1hiGZ0Tw68JWLp2ueU0HJ6n8dO6nymtUImsrtTBZB37uC4BrxZL1OmkPNBpFJpNdMlpWAxTpEeEgQ+YAOetpe9UlhZbbCfIFERxzHftuETGNQHz/4AYCRVHqCMiVJNcILK11V1AD6OsrLB4uhaejYlOySzv27hkBRL4h2QHB17ip/UZv3brRGsBYP8nfHhoeB6hEsVs7iXfqQSYiEERDh2KSmDPvVLVJ/mvg+OnCDprwlYgucpRzrUem66hBkIsZsmZuVHwtJfc4jl287EQLgkObifIeElcDUoLgFCAfKZgPOzoWfdLZ2VmuRtbf/8GC88MX+gVcVv1HyB+Ya3mVg005MtPpbJuhehlgNwlrMlXyqaftW+ulrrpfdyZHJ/z7r9tAq1Ng7gDltNZ28j8DNCo0ld0/bOx/KATgarIAAAAASUVORK5CYII=" alt="">
-
</div>
-
</div>
布局和祝福语一样,刷新按钮换成了单位文本。
这里文本框有个离开焦点事件,如果判断没有输入值,那么提示”请输入数量",并且红包数量只能是正整数,文本框也变为红色边框,默认则为蓝色边框
-
<div class="content-label">
-
<div class="cl-text">
-
<span style="color:#f00;">*</span>
-
<span>红包数量</span>
-
</div>
-
<div class="cl-input">
-
<input placeholder="请填写红包数量" value="" />
-
<span>个</span>
-
</div>
-
</div>
-
$("#txtCount").blur(function () {
-
txtCount = $(this).val();
-
if (txtCount == undefined || txtCount == null || txtCount == '' || txtCount.trim() == '') {
-
$("i", $(this).parent()).show().html('请输入数字!');
-
$(this).parent().addClass('red-border');
-
}
-
else {
-
if (txtCount <= 0) {
-
$("i", $(this).parent()).show().html('请输入有效数字格式!');
-
$(this).parent().addClass('red-border');
-
}
-
else if (!isNaN(txtCount)) {
-
$("i", $(this).parent()).hide();
-
$(this).parent().removeClass('red-border');
-
}
-
else {
-
-
}
-
}
-
});
布局和前面一样,这就是前端布局的魅力,有很多可以重用的东西
-
<div class="content-label">
-
<div class="cl-text">
-
<span style="color:#f00;">*</span>
-
<span>红包总金额</span>
-
</div>
-
<div class="cl-input">
-
<input placeholder="请填写红包总金额" value="" />
-
<span>元</span>
-
</div>
-
</div>
这里的布局和前面稍微多点东西,布局差不多。
这里只做读取展示用,也可以用input输入文本框,设置默认只读即可
-
<div class="content-label">
-
<div class="cl-text">
-
<span style="color:#f00;">*</span>
-
<span>余额支付</span>
-
</div>
-
<div class="cl-input">
-
<label>当前余额:<b>51.25</b> 元</label>
-
<span class="span">前往充值 > </span>
-
</div>
-
</div>
当点击文本框时,先判断是否已经提示无效信息,也就是已经有红色边框,有则不显示蓝色边框,没有则显示蓝色边框。当离开文本框焦点,那么则移除蓝色边框
-
// 文本框点击事件
-
$('.cl-input input').click(function () {
-
var className = $(this).parent().attr('class');
-
if (className.indexOf('red-border') < 0) {
-
$(this).parent().addClass('blue-border');
-
}
-
}).blur(function () {
-
$(this).parent().removeClass('blue-border');
-
});
1)支付额文本
这里布局左定位,金额数字加红色字体
2)取消和确认按钮
取消按钮鼠标移动上去边框变深,直接使用css的hover属性即可完成。
确认按钮的效果使用同样的方式
3)布局效果
4)布局代码
-
<!--按钮-->
-
<div class="button">
-
<div class="price">
-
<span>需支付:</span>
-
<span id="priceSpan" style="font-size:20px;color:#f00;">0.00</span>
-
<span>元</span>
-
</div>
-
<div class="btn">
-
<div class="btnCancel">
-
<span>取消</span>
-
</div>
-
<div class="btnOk not-allowed">
-
<span>确定</span>
-
</div>
-
</div>
-
</div>
5)交互代码
-
// 红包个数
-
var txtCount = 0;
-
var txtPrice = 0;
-
$("#txtCount").keyup(function () {
-
txtCount = $(this).val();
-
$("#priceSpan").html(txtCount * txtPrice);
-
});
-
-
// 红包总金额
-
$("#txtPrice").keyup(function () {
-
txtPrice = $(this).val();
-
$("#priceSpan").html(txtPrice);
-
});
红包数量和红包金额那里还有几个交互和逻辑判断,有兴趣的小伙伴可以自己实现下,有疑问的可咨询了解
完整代码可以查看gitCode:小5聊 / Csdn Red Bag Html · GitCode
| calc()函数 | 可用于高宽度精准布局,更加合理布局 |
| position和relative | 相对和绝对定位,同样有助于合理定位和布局 |
| Math.random() | 随机函数,随机产生0~1的值 |
| keyup() | 键盘弹上事件 |
| click() | 元素点击事件 |
| blur() | 离开焦点事件 |
总结:前端布局,要玩出花样和效果,还是需要点艺术天赋。总之,挺有趣的,刚入门可能会觉得比较难,当你熟练之后,还是挺有趣的!
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
ThingJS 基于 HTML5 和 WebGL 技术,可方便地在主流浏览器上进行浏览和调试,支持 PC 和移动设备。
ThingJS 为可视化应用提供了简单、丰富的功能,只需要具有基本的 Javascript 开发经验即可上手。
ThingJS 提供了场景加载、分层级浏览,对象访问、搜索、以及对象的多种控制方式和丰富的效果展示,可以通过绑定事件进行各种交互操作,还提供了摄像机视角控制、点线面效果、温湿度云图、界面数据展示、粒子效果等各种可视化功能网页链接。
谷歌人工智能写作项目:小发猫
如果可视化平台还觉得太难了,那真的没有简单的了,程序员还得写代码,全靠经验判定呢typescript是用来干什么的,为什么要用typescript。
软件是由程序员编写的代码出现的,一般开发软件需要有UI前端,后台程序员,还有数据库人员等来一起完成一个项目,一般没有专业知识的是没有办法去独立开发一个软件平台的哦。首先要开发软件,需要知道要什么功能?
达到什么效果?最终实现目的。这几个问题搞清楚之后,就可以考虑自己的预算,考虑好了预算之后,才好结合自己的需求,提供给软件开发公司进行沟通,沟通之后,确定价格,这样就可以签合同开始制作啦。
如果有疑问,可以在下面补充,我们一起讨论吧。
HEC-DSSVue是一个基于Java的可视化实用程序,允许用户在HEC-DSS数据库文件中绘制,制表,编辑和操作数据。
HEC-DSSVue生成的图形是高度可定制的,可以以各种格式保存,包括“jpeg”和“png”(便携式网络图形),或者打印或复制到剪贴板以包含在报告中。HEC-DSSVue包含六十多个数学函数。
除了这些函数之外,HEC-DSSVue还提供了几个实用程序函数,这些函数提供了一种将数据集输入到HEC-DSS数据库中、重命名数据集名称、将数据集复制到其他HEC-DSS数据库文件以及删除数据集的方法。
一、AdobeEdge目前还处于预览阶段的AdobeEdge是用HTML5、CSS、JavaScript开发动态互动内容的设计工具。内容可以同时兼容移动设备和桌面电脑。
Edge的一个重要功能是Web工具包界面,方便确保页面在不同浏览器中的架构一致性,此外Edge还将整合T...。
。
前端需要掌握的技术还是很多的1.熟练掌握前端开发技术(HTML5、CSS3、JS、JSON、XHTML),了解各项技术的相关标准;2.掌握Ajax异步编程,能够写出高性能、可复用的前端组件;3.对OO、MVC、MVVM等编程思想、前端框架有深刻理解,熟练掌握至少一个前端框架了解其原理(常用前端框架Vuejs,AngularJS,React,Bootstrap,QUICKUI,移动端有:FrozenUI,weUI,SUI,MUI,AUI);4.善于Web性能优化,可访问性、对SEO等有良好的体验;理解表现层与数据层分离的概念、Web语义化;5.了解前端安全机制,熟悉HTTP协议以及浏览器缓存策略;6.熟悉常见JS开发框架源码实现(如:prototype、jQuery、Mootools,Ext,Dojo,underscore、YUI、Kissy);7.拥有良好的代码编写,设计文档撰写的经验,熟练使用Git等版本控制工具;8.对常见的浏览器兼容问题有清晰的理解,并有可靠的解决方案;如IE6/7/8/9、Firefox、Safari、Chrome。
。
可往3D开发工程师转型,前提要熟练掌握js,熟悉webgl,这里你可以练练手网页链接ThingJS基于HTML5和WebGL技术,可方便地在主流浏览器上进行浏览和调试,支持PC和移动设备。
ThingJS为可视化应用提供了简单、丰富的功能,只需要具有基本的Javascript开发经验即可上手。
ThingJS提供了场景加载、分层级浏览,对象访问、搜索、以及对象的多种控制方式和丰富的效果展示,可以通过绑定事件进行各种交互操作,还提供了摄像机视角控制、点线面效果、温湿度云图、界面数据展示、粒子效果等各种可视化功能。
ThingJS提供如下相关组件和工具供用户使用:CityBuilder:聚焦城市的3D地图搭建工具,打造你的3D城市地图。CamBuilder:简单、好用、免费的3D场景搭建工具。
ThingPano:全景图制作工具,轻松制作并开发全景图应用,实现3D宏观场景和全景微观场景的无缝融合。ThingDepot:上万种模型,数十个行业,自主挑选,一次制作多次复用。
初学者必看干货web前端学习路线图,随着移动互联网的发展,web前端逐渐受到企业的重视,前端开发人员的薪资也水涨船高,越来越多的人看好前端行业的发展,想要转行加入。
下面,给大家分享一份web前端学习路线图,希望对初学者有所帮助。Web前端行业的发展,让前端人员能完成比以前更多的职责范围,所以未来前端可以宽口径就业,前景非常好。
除此之外,目前web前端工程师日均岗位缺口超50000,平均薪资10820元/月。对于零基础的人而言,要怎么学习web前端呢?1、前端页面重构。
主要内容为PC端网站布局、Photoshop工具及切图、H5移动端网页布局、HTML5+CSS3新特性与交互。学习目标是完成PC端网站布局,可实现响应式布局,一套代码适配PC端、移动端、平板设备等。
2、前后端网页交互。
主要内容为JavaScript语法全面进阶、ES6到ES10新语法实践、jQuery应用及插件使用、设计模式及插件编写、封装JS工具库及WebAPIS、AJAX+PHP+MySQL前后端交互、前端工程化与模块化应用以及PC端全栈开发项目等。
学习目标是可以掌握前端工程化工具,如git、gulp、webpack等,搭建项目及开发项目。3、+前端框架。
主要内容为全面进阶、Koa2+MongoDB搭建服务、框架、框架、小程序云开发与小程序框架、原生APP与混合APP、数据可视化与桌面应用等。
学习目标是掌握桌面应用及可视化大数据,实现复杂数据展示类项目,能够独立完成前后台相关功能,胜任HTML5全栈开发工程师职位。
很多学习web前端的朋友都希望在学成后能找到一份满意的工作,所以我们在学习过程中一定要注意实战经验的积累,如果你所学的东西对企业没有用,那你所做的一切都是无用功。
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
1、安装插件—时间格式化插件
npm i silly-datetime --save
2、Main.js文件引用
-
import Time from "silly-datetime"; //时间格式化处理插件
-
Vue.prototype.$Time = Time; //全局使用
3、页面中使用
this.$Time.format(new Date(), 'YYYY-MM-DD HH:mm:ss');
1.安装插件
npm i silly-datetime --save
2.在node中引入
const timeQs = require('silly-datetime'); // 事件格式化控件
3.在后端路由中
obj.time = timeQs.format(new Date(), 'YYYY-MM-DD HH:mm:ss');
4、参数说明
| 格式 | 类型 | 说明 | 实例 |
|---|---|---|---|
| YYYY | 年 | 年份 | YYYY :2019 |
| MM | 月 | 月份,补0 | MM:07 |
| M | 月 | 月份,不补0 | M:7 |
| DD | 日 | 日,补0 | DD:07 |
| D | 日 | 日,不补0 | D:7 |
| HH | 小时 | 24小时,补0 | HH:07 |
| H | 小时 | 24小时,不补0 | H:7 |
| hh | 小时 | 12小时,补0 | hh:07 |
| h | 小时 | 12小时,不补0 | h:7 |
| A | am | 上午 | mm:07 |
| a | pm | 下午 | m:7 |
| mm | 分钟 | 分钟,不补00 | mm:07 |
| m | 分钟 | 分钟,不补0补0 | m:7 |
| s | 秒钟 | 秒钟,不补00 | s:07 |
| s | 秒钟 | 秒钟,不补0补0 | s:7 |
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
在 Node.js 中,您可以使用该fs.readdir()方法列出目录中的所有可用文件。.此方法异步工作以读取给定目录的内容,并返回目录中不包括和的文件名数组..。
这是一个读取目录中所有可用文件并在控制台上打印它们的名称的示例:
-
const fs = require('fs');
-
-
// directory path
-
const dir = './node_modules/';
-
-
// list all files in the directory
-
fs.readdir(dir, (err, files) => {
-
if (err) {
-
throw err;
-
}
-
-
// files object contains all files names
-
// log them on console
-
files.forEach(file => {
-
console.log(file);
-
});
-
});
fs.readdir()如果给定目录不存在,该方法将抛出错误。
该fs模块还提供了 call 的同步变体,readdir()它readdirSync()同步工作并返回文件名数组:
-
const fs = require('fs');
-
-
// directory path
-
const dir = './node_modules/';
-
-
// list all files in the directory
-
try {
-
const files = fs.readdirSync(dir);
-
-
// files object contains all files names
-
// log them on console
-
files.forEach(file => {
-
console.log(file);
-
});
-
-
} catch (err) {
-
console.log(err);
-
}
查看本指南以了解有关在 Node.js 应用程序中读取和写入文件的更多信息
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
web自动化测试作为软件自动化测试领域中绕不过去的一个“香饽饽”,通常都会作为广大测试从业者的首选学习对象,相较于C/S架构的自动化来说,B/S有着其无法忽视的诸多优势,从行业发展趋、研发模式特点、测试工具支持,其整体的完整生态已经远远超过了C/S架构方面的测试价值。接上一篇文章,我们将继续深入探讨Selenium的相关使用方法与技巧。
此篇中所用的技术栈为Selenium+Python,因其本身编程难度不高,总体思想都是基于面向对象的编程理念,故只要大家的编码语言基础不弱,就完全可以做到平替。
在正式启动浏览器之前,这里还需要说说上一篇没有提及的一个问题,后台有同学私信说在对应驱动网站上完全找不到自己浏览器对应版本的驱动,关于浏览器驱动的版本,大家都知道驱动的版本应该是要与浏览器的版本完全对应上的。但往往日常工作中因为环境或者其他客观因素会导致浏览器的版本五花八门,也会出现驱动网站上完全没有你目前工作环境中对应的浏览器版本,这里我们大可使用中版本号一致的驱动来进行尝试,没有必要将版本进行完全的匹配。比如你的Chrome浏览器的版本号为107.0.5304.107,如果这时对应网站只有107.0.5304.62与108.0.5359.22的前后两个版本的驱动比较相近,这里就有两个选择,第一就是卸掉原有的浏览器,安装对应的版本;第二则是选择107.0.5304.62来进行尝试;相信大家在成本耗时的判断下,一般都会选择第二个选项来进行尝试对吧?那么我可以很负责任的告诉你,第二个判断是完全行的通的。不必太过纠结驱动的小版本号是否完全匹配。
我们将一切准备就绪后就可以开始我们的selenium之旅了,首先我们需要将使用selenium进行浏览器的启动(访问百度)。
from selenium import webdriver
browser = webdriver.Chrome() browser.get('https://www.baidu.com')
如果对应的浏览器驱动没有进行环境变量的设置,可以在代码中直接进行程序的路径指定来进行后续的浏览器操作。
from selenium import webdriver
path = r'C:\Program Files\Google\Chrome\Application\chromedriver.exe' browser = webdriver.Chrome(path) browser.get('https://www.baidu.com')
使用Selenium打开后的浏览器都会标识出正在受到自动化测试软件控制的相关提示。
Selenium本身提供给了我们非常多的各类浏览器与页面的操作函数,方便我们根据所需测试业务来进行自由搭配使用甚至是二开。
对于浏览器窗口的尺寸进行控制与获取,如最大化、最小化、指定窗口大小等。
窗口全屏
browser.fullscreen_window()
窗口最大化
browser.maximize_window()
窗口最小化
browser.minimize_window()
自定义窗口大小(宽X高)
browser.set_window_size(1080, 720)
自定义窗口坐标位置与大小(x坐标,y坐标,宽X高)
browser.set_window_rect(100, 200, 1080, 720)
获取窗口的大小(宽X高)
browser.get_window_size()
获取窗口的坐标位置,返回一个字典对象
browser.get_window_position()
获取窗口的坐标与大小(x坐标,y坐标,宽X高)
browser.get_window_rect()
获取当前窗口的句柄
browser.current_window_handle
获取当前所有窗口的句柄
browser.window_handles
对于浏览器当前页面的一些操作,如前进、后退、刷新等。
前进(下一页面)
browser.forward()
后退(上一页面)
browser.back()
刷新(当前页面)
browser.refresh()
截图并保存为test.png(当前页面)
browser.save_screenshot('test.png')
截图并保存为png文件(当前页面)
browser.get_screenshot_as_file('test_02.png')
截图并将信息转为base64编码的字符串
browser.get_screenshot_as_base64()
对于浏览器当前一些信息的获取与操作。
获取页面URL(当前页面)
browser.current_url
获取日志类型,会返回一个列表对象
browser.log_types
获取浏览器操作日志,注意函数内的参数为固定值类型’browser’
browser.get_log('browser')
获取设备操作日志,参数原理同上
browser.get_log('driver')
获取当前页面标题
browser.title
获取当前浏览器的名字
browser.name
Selenium中最基础也是最重要的一环,基本上对于页面的业务操作大多数都集中与此。另外需要注意的是元素定位所使用的find_element_by的方法在很早之前就已经被废弃,这里同样也会使用最新的find_element方法进行讲解。
如何查看页面中的元素与其相关属性,这里以Chrome为例,我们只需按F12或者右键页面选择“检查”,再点击调试窗口的左上角的箭头标志或者使用快捷键Ctrl+Shift+C来进行元素的选取,此时Elements标签页中会将焦点对应跳转至该元素的html代码行中,接下来我们就可以针对不同的元素和不同的属性来进行定位操作。
通过一个元素的name属性来进行定位。
比如定位百度中的搜索栏,我们通过name属性来进行定位。该元素的html构造如下:
<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">
我们只需将name属性后面的值拿出,赋予给find_element方法即可。新的By方法我们只需要导入selenium.webdriver.common.by下的By方法即可。
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') sleep(2) browser.find_element(By.NAME, 'wd')
通过一个元素的class属性来进行定位。
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') sleep(2) browser.find_element(By.CLASS_NAME, 's_ipt')
通过一个元素的id属性来进行定位。
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') sleep(2) browser.find_element(By.ID, 'kw')
css selector也被成为选择器定位,它通过页面内的元素的id、name、tag三个属性来进行定位,根据元素属性的重复程度,可以单独属性定位也可组合属性来进行定位。而且相较于xpath定位方式来说,博主更推荐使用此方法来进行定位,无论是易用度还是维护性来说比xpath定位好的多。
单属性定位–tag属性
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') sleep(2) browser.find_element(By.CSS_SELECTOR, 'input')
单属性定位–id属性
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') sleep(2) browser.find_element(By.CSS_SELECTOR, '#kw')
单属性定位–class属性
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') sleep(2) browser.find_element(By.CSS_SELECTOR, '.s_ipt')
多属性定位–tag+id属性
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') sleep(2) browser.find_element(By.CSS_SELECTOR, 'input#kw')
多属性定位–tag+class属性
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') sleep(2) browser.find_element(By.CSS_SELECTOR, 'input.s_ipt')
同样的,其他的组合方式大家可以举一反三,不断尝试,比如模糊匹配input[class ~= "局部关键字"]、层级定位#form > span > input等等等等。
这种定位方式适用于页面中带有超链接的元素,直接通过超链接标签内的文字进行元素定位。
我们以百度首页为例,可以看到该页面中有很多的超链接标签,如果我们想模拟点击跳转至新闻对应页面的操作,就可以用link text的元素定位方法来进行实现。

使用超链接标签对中的“新闻”一词来进行定位。
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') sleep(2) browser.find_element(By.LINK_TEXT, '新闻').click()
这个定位方式与link text定位十分相像,实际上也就是link text的模糊查找定位方式,对象也是超链接内的文字,只不过他匹配的不是全部文字而是局部。
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') sleep(2) browser.find_element(By.PARTIAL_LINK_TEXT, '新').click()
tag定位的效率总体来说不高,也不太推荐单独使用,html页面中一般也是由很多相同或不同的标签对组成。就tag而言标签重复的越多,定位的效率其实也就越低。
比如我们想在百度的搜索栏中输入“selenium”关键字,那么光使用tag其实就很难达到我们的目的,甚至无法准确定位到我们想要的元素。如果运气好,搜索栏的input标签在html页面中排在第一位那还好,只要不是第一位,我们就需要编写其他的代码逻辑来辅助我们继续定位这个元素。
所以下面的代码实在是不能称之为高效的执行代码
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') sleep(2) browser.find_element(By.TAG_NAME, 'input').send_keys('selenium')
一般来说无法通过以上的这些元素定位方法定位的情况下,我们会使用xpath定位方法。但这里需要特别注意,xpath方法分为绝对路径和相对路径两种定位方式,博主只推荐如果真要使用xpath就使用相对路径+正则表达式的方式来进行元素定位。不推荐绝对路径的原因就不用博主多说了吧,只要你敢用,后期的脚本维护与复用绝对会让你抓狂的。
还是老样子,我们使用xpath的相对路径写法来定位百度首页的搜索栏。
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') sleep(2) browser.find_element(By.XPATH, '//*[@id="kw"]').send_keys('selenium')
另外与find_element方法相对应的find_elements方法这里就不多做介绍了,该种方法是将当前页面中所有能匹配上对应元素定位方法的元素全部获取。大家可以根据自己的需求来进行选取和使用。
我们加载页面时通常会因为网络环境等各方面的客观因素而导致元素加载的速度各不相同,如果此时我们没有对业务操作进行一定的延时执行,那么大概率业务操作会出现各类的no such element报错。
那么我们就需要在页面元素加载完成之后再对相应的元素进行业务操作来规避上面说的这个问题。Selenium内可以使用三种延时的函数来进行对应的延时业务操作。
隐式等待的作用是在页面加载是隐性的进行特定时长的等待,如果在规定的等待时长内页面加载完毕,则会继续进入下一个业务操作,如果没有加载完毕,则会抛出一个超时的异常。这里其实有两个问题,第一,隐式等待是全局性质的,也就是说一旦你设置了个5秒,那整个程序都会使用这个等待时间类进行配置,灵活性较低;第二,如果碰到了有些页面中的元素是局部加载的话,那整个页面的加载是否完成也就没有了其意义,隐式加载无法针对这样的情况作出调整,智能度较低。所以一般来说只要是对于页面的整体加载要求不高或者元素的加载比较稳定的程序,都可以使用隐式等待来进行延时操作。
from selenium import webdriver from selenium.webdriver.common.by import By
browser = webdriver.Chrome() browser.get('https://www.baidu.com') browser.implicitly_wait(5) browser.find_element(By.XPATH, '//*[@id="kw"]').send_keys('selenium')
显式等待的作用则是使用特定的等待时长来进行某些业务逻辑判断,如果判断(比如元素是或否加被定位)在时间完成那继续执行下一个业务操作,如果判断失败也会抛出no such element的异常,而显式等待的默认检查元素周期为0.5秒。乍一看好像与隐式等待差不多,其实不然,首先显式等待是针对页面中某个或某组特定元素而执行的,隐式则是全局,对所有的元素都生效;其二,显式等待可以通过自定义条件来进行元素的定位和选取,隐式则不行。
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC
browser = webdriver.Chrome() browser.get('https://www.baidu.com') ele = WebDriverWait(browser, 10, 0.5).until(EC.presence_of_element_located((By.XPATH, '//*[@id="kw"]'))) ele.send_keys('selenium')
这个应该是平时大家代码中用的最多的等待方式了吧,sleep是针对线程进行挂起的一种等待方式,等待时长根据指定的参数来进行决定。最大的好处就是简单粗暴,无任何逻辑在里面,所以也被称为强制等待。
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') sleep(2) browser.find_element(By.XPATH, '//*[@id="kw"]').send_keys('selenium')
那么以上的三种等待方式其实各有各的特点与缺点,三者之间没有绝对的好用和不好用,而在我们的日常工作场景中也希望大家可以根据实际的情况有选择性的使用。
元素加载超时我们可以使用以上三种延时方式来进行处理,那么页面超时了又该如何操作呢?selenium也为我们准备了两个函数来对应这样的局面。
页面加载超时
browser.set_page_load_timeout(30)
这里推荐将超时的时间有效的拉长,不宜过短。过短的超时时间容易导致整体页面出现未加载html代码情况下直接令驱动无法工作的情况。
页面异步js或ajax操作超时
browser.set_script_timeout(30)
这个函数是用于execute_async_script()相关的异步js操作超时报错,由于是异步操作,等待时间同理也不易过短。
浏览器中键盘与鼠标的操作也是不可或缺的重要一环,在被测对象的业务要求中往往占有不少的戏份。
文字输入
browser.find_element(By.ID, 'kw').send_keys('selenium')
点击
browser.find_element(By.ID, 'kw').click()
点击并按住不放(左键长按),这些模拟鼠标操作需要导入ActionChains包
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele = browser.find_element(By.ID, 'kw') act.click_and_hold(ele).perform()
右键点击
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele = browser.find_element(By.ID, 'kw') act.context_click(ele).perform()
双击
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele = browser.find_element(By.ID, 'kw') act.double_click(ele).perform()
拖拽元素至另一个元素处,ele_a 为source,ele_b 为target
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele_a = browser.find_element(By.ID, 'btn_a') ele_b = browser.find_element(By.ID, 'btn_b') act.drag_and_drop(ele_a, ele_b).perform()
拖拽元素至指定位置后松开,元素后为x,y坐标值
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele = browser.find_element(By.ID, 'btn_a') act.drag_and_drop_by_offset(ele, 200, 100).perform()
鼠标移动至指定元素
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele = browser.find_element(By.ID, 'btn_a') act.move_to_element(ele).perform()
按下指定的键位(示例代码中是回车键)
from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele = browser.find_element(By.ID, 'kw').send_keys('selenium') act.key_down(Keys.ENTER).perform()
松开指定的键位,这里也可以用链式写法
from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele = browser.find_element(By.ID, 'kw').send_keys('selenium') act.key_down(Keys.ENTER) act.key_up(Keys.ENTER) # 链式写法 act.key_down(Keys.ENTER).act.key_up(Keys.ENTER).perform()
移动鼠标到指定坐标位置
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele = browser.find_element(By.ID, 'kw').send_keys('selenium') act.move_by_offset(100, 200).perform()
移动到距离指定元素多少距离的位置(从左上角0, 0开始计算)
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele = browser.find_element(By.ID, 'kw').send_keys('selenium') act.move_to_element_with_offset(ele, 100, 200).perform()
在指定元素位置松开鼠标
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele = browser.find_element(By.ID, 'kw').send_keys('selenium') act.click_and_hold(ele).release(ele).perform()
发送指定的键或者内容至指定元素
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele = browser.find_element(By.ID, 'kw').send_keys('selenium') act.send_keys_to_element(ele, 'selenium').perform()
暂停所有操作,默认单位为秒
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele = browser.find_element(By.ID, 'kw').send_keys('selenium') act.context_click(ele).pause(5).double_click(ele).perform()
页面中也存在着很多不同种类的组件,比如单选框、多选框、下拉列表、选项卡等。这些操作也可以通过selenium提供的函数进行实现。
清除指定元素中的内容(输入框等)
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele = browser.find_element(By.ID, 'kw') ele.send_keys('selenium') sleep(2) ele.clear()
提交确认(类似于Keys.ENTER的效果)
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains from time import sleep
browser = webdriver.Chrome() browser.get('https://www.baidu.com') act = ActionChains(browser) ele = browser.find_element(By.ID, 'kw') ele.send_keys('selenium') sleep(2) ele.submit()
下拉列表,我们就可以使用Select方法来实现选取操作
使用Select方法需要从selenium.webdriver.support.select导入该方法
例如下图中某网站的下拉列表对象
html构造如下
select_by_index()方法
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.select import Select
browser = webdriver.Chrome() browser.get('https://www.xxxx.com') ele = browser.find_element(By.ID, 'input_factor_gj_count') # 需要注意下标要从0开始,选择1%那一项 Select(ele).select_by_index('0')
select_by_value()方法
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.select import Select
browser = webdriver.Chrome() browser.get('https://www.xxxx.com') ele = browser.find_element(By.ID, 'input_factor_gj_count') # 指定元素的value属性值,选择1%那一项 Select(ele).select_by_value('0.01')
select_by_value()方法
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.select import Select
browser = webdriver.Chrome() browser.get('https://www.xxxx.com') ele = browser.find_element(By.ID, 'input_factor_gj_count') # 指定元素的文本值,选择1%那一项 Select(ele).select_by_visible_text('1%')
框架切换(Frame)
如果在页面中定位某一个元素失败并检查其属性并没有问题时,就该考虑是否在祖先节点中是否存在frame或者iframe标签。这样的页面就表名存在多层框架嵌套,这时我们就需要进行框架切换的操作,来准确定位到指定元素。
例如某页面存在两层frame嵌套,内部框架的xpath为://*[@id="mainDiv"]/iframe,此时如果定位某个输入框失败之后,我们就应该转而跳入该frame内进行元素定位。
from selenium import webdriver from selenium.webdriver.common.by import By
browser = webdriver.Chrome() browser.get('https://www.xxxx.com') # 定位到指定的frame path = browser.find_element(By.XPATH, '//*[@id="mainDiv"]/iframe') # 切换至该frame内 browser.switch_to_frame(path) ele = browser.find_element(By.CLASS_NAME, 'input') ele.send_keys('selenium')
标签页切换
我们浏览器在使用中一般会打开多个浏览窗口,也就是多个标签页。此时我们就可以通过每个标签页的句柄来进行定位和互相切换。
switch_to_window()
我们利用浏览器窗口的句柄来进行标签页的切换
from selenium import webdriver from selenium.webdriver.common.by import By
browser = webdriver.Chrome() browser.get('https://www.baidu.com') # 第一个窗口的句柄下标为0,打开第二个就是1 browser.switch_to_window(browser.window_handles[1]) # 此时就会使用第二个标签页去访问淘宝 browser.get('https://www.taobao.com')
弹窗处理
页面中时常也存在着各类的弹窗,比如警告、确认、提示等等,那么对于这些弹窗我们也有着相应的业务处理方法。
首先我们需要明确的是每种类型的弹窗中元素也是各不相同,所以我们针对不同的弹窗使用不同的属性来定位和操作。
警告弹窗
一般来说就是告知到使用者执行某些操作与页面之后将要注意的事项,这种窗口只需确认。
from time import sleep from selenium import webdriver from selenium.webdriver.common.by import By
browser = webdriver.Chrome() browser.get('https://www.xxxx.com') browser.find_element(By.ID, 'btn_tg_title').click() sleep(1) # 在警告弹窗中点击确认按钮 browser.switch_to_alert().accept()
确认弹窗
多用于在用户执行提交操作后的动作确认,有确认和取消两个选项。
from time import sleep from selenium import webdriver from selenium.webdriver.common.by import By
browser = webdriver.Chrome() browser.get('https://www.xxxx.com') browser.find_element(By.ID, 'btn_submit').click() sleep(1) #确认二选一 browser.switch_to_alert().accept() #取消二选一 browser.switch_to_alert().dismiss()
提示弹窗
这个通常用来处理用户信息交互的场景,用户可以通过弹窗输入一些文字信息,来传递与进行后续的业务处理。
from time import sleep from selenium import webdriver from selenium.webdriver.common.by import By
browser = webdriver.Chrome() browser.get('https://www.xxxx.com') browser.find_element(By.ID, 'btn_info_inquiry').click() sleep(1) # 这里传递信息到提示弹窗,警告与确认两类弹窗不可使用,会报错 browser.switch_to_alert().send_keys('20100909')
既然是web自动化测试,那我们又怎么能少了Cookie的相关操作呢?用户的状态和业务请求都的需要用他来进行鉴权。在selenium中对Cookie进行操作其实也很简单,首先我们需要手动的登录被测网站一次,待网站Cookie存入本地后即可使用Selenium自带的函数对齐进行业务操作。
首先我们获取对应网站的Cookie值
import json from selenium import webdriver
browser = webdriver.Chrome() browser.get('https://www.baidu.com') # 写入保存为文件还是直接打印至控制台,各取所需 with open('cookies.txt', 'w') as f: f.write(json.dumps(browser.get_cookies())) cookies = browser.get_cookies() print(cookies)
接下来我们简单的对获得的Cookie进行处理
# 删除所有的cookies browser.delete_all_cookies() # 循环打印cookie中的name和value for c in cookies: # 查看打印出的cookie对应的键值对 print("%s : %s" % (c['name'], c['value'])) # 根据自己的业务需求进行cookie的增删改 cookie = {"name": "xxxx", "value": "xxxx"} # 最后添加即可 driver.add_cookie(cookie)
Selenium也为我们提供了可执行js脚本相关的函数,他们的作用是在某些页面中模拟一些业务动作(画面滑动,选择日期等)。在一些仅靠webdriver无法实现的业务场景中,我们就可以依靠此函数来辅助测试目的的达成。
js的查找元素方法(ID)
document.getElementById("id")
js的查找元素方法(name)
document.getElementsByName('name')
js的查找元素方法(class)
document.getElementsByClassName("class_name")
js的查找元素方法(tag)
document.getElementsByTagName('tag_name')
js的查找元素方法(css)
document.querySelector("css selector")
js的查找元素方法(css_list)
document.querySelectorAll("css selector")
execute_script()
从上可以看出其实js的定位元素方法和selenium中的差不多,接下来我们就可以将需要执行的js语句放入到执行函数中使用。
from selenium import webdriver
browser = webdriver.Chrome() browser.get('https://www.baidu.com') # 定位后修改指定元素的value属性 js_script_exec = 'document.getElementById("form_motion").value="list_modify";' browser.execute_script(js_script_exec)
对于某些动态div标签(窗口),一般的方法不太奏效的情况下,可以尝试下switch_to_default_content()方法,跳转到最外层;
使用模拟键鼠操作的时候,无论是单独使用还是链式写法,记得在结尾加上perform()方法进行执行;
如果元素定位时报错element click intercepted,记得检查界面上是否有其他元素进行覆盖,元素有可能也是具有隐藏属性的;
元素过期报错element is not attached to the page document,可以尝试重新刷新页面,这里不推荐直接使用refresh方法,还是养成好习惯先怼上try…except…捕捉到异常后在进行刷新或重置操作;
对于属性值为动态的元素,墙裂推荐使用CSS selector或者xpath方法来进行元素定位,正则表达式也推荐大家最好能掌握;
如果前期对xpath的相对路径写法比较头疼,推荐使用F12调试工具自带的元素复制功能,在你想要复制的元素所在的标签对这行右键,选择copy —— Copy XPath选项即可;
输入框默认存在内容想要删除再输入信息的话,不推荐模拟键盘操作Ctrl+A,然后模拟退格键,试试clear()方法吧;
抓不到元素可以使用延时方法,输入文字也是一样的道理,业务场景中需要大量输入文字的,无论是从文件中还是提取又或者是遍历,出现少字漏字的话,同样也可以使用延时的方法,适当的放慢处理的速度;
在页面中总会有些不可见的元素,这种情况使用is_displayed()方法即可快速定位找到;
有些被测页面需要验证码,无论是手机的还是图片验证,和开发同学沟通一下,留个万能的就行了,其本身的功能手工回归一下即可,不必太过纠结;
三方登录功能也是如此,不推荐直接使用web自动化去搞,三方的一般是不开源的,有这折腾的时间还不如跑跑接口和黑盒,自动化的话绕过去即可;
自动化测试用例这块的话博主还是推荐不要有依赖,和功能测试用例同理,每次的执行顺序或者数量都会根据需求与业务场景发生变化,一旦依赖了会大大增加测试同学的维护成本,后面有空我会单独出一期自动化测试用例的文章来为大家介绍。
分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务、UI设计公司、界面设计公司、UI设计服务公司、数据可视化设计公司、UI交互设计公司、高端网站设计公司、UI咨询、用户体验公司、软件界面设计公司
蓝蓝设计的小编 http://www.lanlanwork.com