文章來源:人人都是產品經理 作者:新榜
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
需要代碼文末公眾號找我 回復【春聯】即可獲取
index.html
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <title>css3春聯切換</title> <link rel="stylesheet" href="css/style.css"> </head> <body> <div class="rotating-text"> <p>春聯Show</p> <p> <span class="word alizarin">上聯:這個需求很簡單</span> <span class="word wisteria">下聯:怎么實現我不管</span> <span class="word peter-river">橫批:明天上線!</span> </p> </div> <script src="js/script.js"></script> </body> </html>
style.css
@import url(https://fonts.googleapis.com/css?family=Lato:600); body { display: flex; justify-content: center; align-items: center; height: 100vh; background: #222; } .rotating-text { font-family: Lato, sans-serif; font-weight: 600; font-size: 36px; color: white; transform: translateX(-80px); } .rotating-text p { display: inline-flex; margin: 0; vertical-align: top; } .rotating-text p .word { position: absolute; display: flex; opacity: 0; } .rotating-text p .word .letter { transform-origin: center center 25px; } .rotating-text p .word .letter.out { transform: rotateX(90deg); transition: 0.32s cubic-bezier(0.6, 0, 0.7, 0.2); } .rotating-text p .word .letter.in { transition: 0.38s ease; } .rotating-text p .word .letter.behind { transform: rotateX(-90deg); } .alizarin { color: #e74c3c; } .wisteria { color: #8e44ad; } .peter-river { color: #3498db; } .emerald { color: #2ecc71; } .sun-flower { color: #f1c40f; }
![]()
script.js
var words = document.querySelectorAll(".word"); words.forEach(function (word) { var letters = word.textContent.split(""); word.textContent = ""; letters.forEach(function (letter) { var span = document.createElement("span"); span.textContent = letter; span.className = "letter"; word.append(span); }); }); var currentWordIndex = 0; var maxWordIndex = words.length - 1; words[currentWordIndex].style.opacity = "1"; var rotateText = function () { var currentWord = words[currentWordIndex]; var nextWord = currentWordIndex === maxWordIndex ? words[0] : words[currentWordIndex + 1]; // rotate out letters of current word Array.from(currentWord.children).forEach(function (letter, i) { setTimeout(function () { letter.className = "letter out"; }, i * 80); }); // reveal and rotate in letters of next word nextWord.style.opacity = "1"; Array.from(nextWord.children).forEach(function (letter, i) { letter.className = "letter behind"; setTimeout(function () { letter.className = "letter in"; }, 340 + i * 80); }); currentWordIndex = currentWordIndex === maxWordIndex ? 0 : currentWordIndex + 1; }; rotateText(); setInterval(rotateText, 4000);
![]()
1.當缺少庫時會有相應提示 黑窗口執行下方命令+包名即可下載安裝
2.博主此處用的idea 直接Alt+Enter直接下載就成了
3.idea配置python環境也可以參考此文:Python(含PyCharm及配置)下載安裝以及簡單使用(Idea)
import io from PIL import Image #import numpy as np import requests def get_word(ch, quality): """獲取單個漢字(字符)的圖片
ch - 單個漢字或英文字母(僅支持大寫)
quality - 單字分辨率,H-640像素,M-480像素,L-320像素
""" fp = io.BytesIO(requests.post(url='http://xufive.sdysit.com/tk', data={'ch': ch}).content) im = Image.open(fp) w, h = im.size if quality == 'M': w, h = int(w * 0.75), int(0.75 * h) elif quality == 'L': w, h = int(w * 0.5), int(0.5 * h) return im.resize((w, h)) def get_bg(quality): """獲取春聯背景的圖片""" return get_word('bg', quality) def write_couplets(text, HorV='V', quality='L', out_file=None): """生成春聯
text - 春聯內容,以空格斷行
HorV - H-橫排,V-豎排
quality - 單字分辨率,H-640像素,M-480像素,L-320像素
out_file - 輸出文件名
""" usize = {'H': (640, 23), 'M': (480, 18), 'L': (320, 12)} bg_im = get_bg(quality) text_list = [list(item) for item in text.split()] rows = len(text_list) cols = max([len(item) for item in text_list]) if HorV == 'V': ow, oh = 40 + rows * usize[quality][0] + (rows - 1) * 10, 40 + cols * usize[quality][0] else: ow, oh = 40 + cols * usize[quality][0], 40 + rows * usize[quality][0] + (rows - 1) * 10 out_im = Image.new('RGBA', (ow, oh), '#f0f0f0') for row in range(rows): if HorV == 'V': row_im = Image.new('RGBA', (usize[quality][0], cols * usize[quality][0]), 'white') offset = (ow - (usize[quality][0] + 10) * (row + 1) - 10, 20) else: row_im = Image.new('RGBA', (cols * usize[quality][0], usize[quality][0]), 'white') offset = (20, 20 + (usize[quality][0] + 10) * row) for col, ch in enumerate(text_list[row]): if HorV == 'V': pos = (0, col * usize[quality][0]) else: pos = (col * usize[quality][0], 0) ch_im = get_word(ch, quality) row_im.paste(bg_im, pos) row_im.paste(ch_im, (pos[0] + usize[quality][1], pos[1] + usize[quality][1]), mask=ch_im) out_im.paste(row_im, offset) if out_file: out_im.convert('RGB').save(out_file) out_im.show() text = '思前想后幾行代碼筑萬載春秋 扶內保外一千精英帶五千干將' #對聯內容 write_couplets(text, HorV='V', quality='M', out_file='春聯.jpg') #生成普天同慶.jpg對聯圖片
11
222
文章來源:csdn 作者:白大鍋 分享此文一切功德,皆悉回向給文章原作者及眾讀者.
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
異步與同步是相反的
簡單來理解就是:同步按你的代碼順序執行,異步不按照代碼順序執行,異步的執行效率更高。
在前端編程中(甚至后端有時也是這樣),我們在處理一些簡短、快速的操作時,例如計算 1 + 1 的結果,往往在主線程中就可以完成。主線程作為一個線程,不能夠同時接受多方面的請求。所以,當一個事件沒有結束時,界面將無法處理其他請求。
現在有一個按鈕,如果我們設置它的 onclick 事件為一個死循環,那么當這個按鈕按下,整個網頁將失去響應。
為了解決類似這種問題,JavaScript 中的異步操作函數往往通過回調函數來實現異步任務的結果處理。
回調函數就是一個函數,它是在我們啟動一個異步任務的時候就告訴它:等你完成了這個任務之后要干什么。這樣一來主線程幾乎不用關心異步任務的狀態了,他自己會善始善終。
例如:
-
<!DOCTYPE html>
-
<html lang="en">
-
<head>
-
<meta charset="UTF-8">
-
<meta http-equiv="X-UA-Compatible" content="IE=edge">
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
-
<title>回調</title>
-
</head>
-
<body>
-
<button>點擊</button>
-
<p></p>
-
<script>
-
var btn = document.querySelector('button');
-
function fn1(){
-
btn.onclick = function(){
-
document.querySelector('p').innerHTML = '我出現了!'
-
}
-
}
-
setTimeout(fn1,1000)
-
</script>
-
</body>
-
</html>
它的第一個參數是個回調函數,第二個參數是毫秒數,這個函數執行之后會產生一個子線程,子線程會等待 1 秒,然后執行回調函數 "fn1",在命令行輸出 "我出現了!"。
語法格式:
-
new Promise(function (resolve, reject) {
-
console.log("Run");
-
});
resolve和reject是參數
再看這個例子:
-
new Promise(function (resolve, reject) {
-
var a = 0;
-
var b = 1;
-
if (b == 0) reject("Divide zero");
-
else resolve(a / b);
-
}).then(function (value) {
-
console.log("a / b = " + value);
-
}).catch(function (err) {
-
console.log(err);
-
}).finally(function () {
-
console.log("End");
-
});
這段打印結果為:
這三個方法的參數都是一個函數,
.then() 可以將參數中的函數添加到當前 Promise 的正常執行序列,
.catch() 則是設定 Promise 的異常處理序列,
.finally() 是在 Promise 執行的最后一定會執行的序列。 .then() 傳入的函數會按順序依次執行,有任何異常都會直接跳到 catch 序列:
-
new Promise(function (resolve, reject) {
-
console.log(1111);
-
resolve(2222);
-
}).then(function (value) {
-
console.log(value);
-
return 3333;
-
}).then(function (value) {
-
console.log(value);
-
throw "An error";
-
}).catch(function (err) {
-
console.log(err);
-
});
打印結果為:
1111 2222 3333 An error
resolve() 中可以放置一個參數用于向下一個 then 傳遞一個值,then 中的函數也可以返回一個值傳遞給 then。但是,如果 then 中返回的是一個 Promise 對象,那么下一個 then 將相當于對這個返回的 Promise 進行操作,這一點從剛才的計時器的例子中可以看出來。
reject() 參數中一般會傳遞一個異常給之后的 catch 函數用于處理異常。
但是請注意以下兩點:
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
本文重點
函數案例
函數作為參數使用
arguments
作用域:寫代碼要注意變量的在哪聲明和使用的問題
預解析:什么叫預解析, 什么東西發生了什么事
聲明的變量是使用var聲明的,那么這個變量就是全局變量,
全局變量可以在頁面的任何位置使用
除了函數以外,其他的任何位置定義的變量都是全局變量
如果頁面不關閉,那么就不會釋放,就會占空間,消耗內存
全局作用域:全局變量的使用范圍
在函數內部定義的變量,是局部變量,外面不能使用
局部作用域:局部變量的使用范圍
注意:
塊級作用域:一對大括號就可以看成是一塊,在這塊區域中定義的變量,只能在這個區域中使用,但是在js中在這個塊級作用域中定義的變量,外面也能使用;
說明:js沒有塊級作用域,只有函數除外
隱式全局變量:聲明的變量沒有var,就叫隱式全局變量
全局變量是不能被刪除的,隱式全局變量是可以被刪除的
定義變量使用var是不會被刪除的,沒有var是可以刪除的
function f1() {
number=1000;//是隱式全局變量
}
f1();
console.log(number);
var num1=10;
num2=20;
delete num1;//把num1刪除了
delete num2;//把num2刪除了
console.log(typeof num1);
console.log(num1+10);
console.log(typeof num2);
num=100;
console.log(num);
function f1() {
var num=100;
num+=10;
}
f1();//這個函數結束之后
{
var num=10;
console.log(num);//10
}
console.log(num);
if(true){
var num=10;
}
console.log(num);
for(var i=0;i<5;i++){
var number=20;
}
console.log(number);
var i=0;
while (i<5){
var num=100;
i++;
}
console.log(num);
function f1() {
var num=10;
}
f1();
console.log(num);
var num=10;
console.log(num);//10
var num=10;
function f1() {
var num=20;
function f2() {
var num=30;
function f3() {
var num=50;
console.log(num);
}
f3();
}
f2();
}
f1();
function getMax(num1, num2) {
return num1 > num2 ? num1 : num2;
}
console.log(getMax(10,20));
//console.log(getMax);//函數的代碼
function getMax(num1, num2) {
return num1 > num2 ? num1 : num2;
}
var num1=10;
var num2=20;
//函數外面的num1和函數的形參num1不是同一個變量
var result=getMax(num1,num2);
console.log(result);
console.log(getMax);//函數的代碼
function getThreeMax(x, y, z) {
return x > y ? (x > z ? x : z) : (y > z ? y : z);
}
console.log(getThreeMax(10,2,24));
判斷一個數是否是素數(質數),只能被1和自身整除,質數是從2開始
用這個數字和這個數字前面的所有的數字整除一次(沒有1的,沒有自身的)
function isPrimeNumber(num) {
for (var i = 2; i < num; i++) {
if (num % i == 0) {
//說明有一個數字整除了,就沒有必要向后繼續整除了,
//此時就已經驗證出不是質數
return false;
}
}
return true;
}
// console.log(isPrimeNumber(7) ? "yyyyyes" : "nnnnnno")
var aa = isPrimeNumber(17);
if (aa) {
console.log("yes");
} else {
console.log("no");
}
function isPrimeNumber(num) {
for(var i=2;i<num;i++){
if(num%i==0){
//說明有一個數字整除了,就沒有必要向后繼續整除了,此時就已經驗證出不是質數
return false;
}
}
return true;
}
console.log(isPrimeNumber(8)?"是質數":"不是質數");
var result=isPrimeNumber(2);
if(result){
console.log("這個數字是質數");
}else{
console.log("這個數字不是質數");
}
function aaa(x,y){
return x-y;
}
console.log(aaa(99,88))
function reverseArray(arr) {
for (var i = 0; i < arr.length / 2; i++) {
var temp = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = temp;
}
return arr;
}
console.log(reverseArray([1, 2, 3, 4, 5]));
function sortArray(arr) {
//控制比較的輪數
for (var i = 0; i < arr.length - 1; i++) {
//控制每一輪的比較次數
for (var j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}//end if
}//end for
}//end for
return arr;
}
console.log(sortArray([0, 19, 34, 10, 100, 2]));
function getJieCheng(num) {
var result = 1;
for (var i = 1; i <= num; i++) {
result *= i;
}
return result;
}
console.log(getJieCheng(5));//1*2*3*4*5
function getFib(num){
var num1=1;
var num2=1;
var num3=0;
for(var i=3;i<=nnum;i++){
sum=num1+num2;
num1=num2;
num2=sum;
}
return sum;
}
console.log(getFib(12))
函數是有數據類型,數據類型:是function類型的
函數可以作為參數使用,如果一個函數作為參數,那么我們說這個參數(函數)可以叫回調函數 只要是看到一個函數作為參數使用了,那就是回調函數
function sayHi(fn) {
console.log("GOOD");
fn();//fn此時應該是一個函數
}
function suSay() {
console.log("HELLO");
}
sayHi(suSay);
function f1(x,y) {
console.log(x+y);
}
f1(10,20);
function f2(x,y) {
console.log(x+y);
}
f2("HLS","MISS");
function f3(x) {
console.log(x);
}
f3(true);
定義一個函數,如果不確定用戶是否傳入了參數,或者說不知道用戶傳了幾個參數,沒辦法計算,但是如果在函數中知道了參數的個數,等于也知道了每個參數的值.
//定義
function f1() {
//獲取的是函數在調用的時候,傳入了幾個參數
//console.log(arguments.length);
//使用arguments對象可以獲取傳入的每個參數的值
console.log(arguments);
}
f1(10,20,30,40,100,200);//調用
function f1() {
//arguments----->數組使用------偽數組---
var sum=0;
for(var i=0;i<arguments.length;i++){
sum+=arguments[i];
}
return sum;
}
console.log(f1(10,20,30));
預解析:就是在解析代碼之前,預解析做什么事?
把變量的聲明提前了----提前到當前所在的作用域的最上面
函數的聲明也會被提前—提前到當前所在的作用域的最上面
函數調用的時候, 把會函數的聲明提升到作用域的上面
f1();//調用
var num=20;//這個變量的聲明會提升到變量使用之前
function f1() {
console.log(num);
//var num=10;
}
function f1() {
console.log("小蘇好猥瑣");
}
f1();
function f1() {
console.log("小蘇沒有助教猥瑣");
}
f1();
var num;
console.log(num);
num=10;
function f1() {
console.log("哈哈,助教好猥瑣哦");
}
//f1();//報錯
注意:預解析中,變量的提升,只會在當前的作用域中提升,提前到當前的作用域的最上面
function f1() {
console.log(num);//undefined
var num = 10;
}
f1();
console.log(num);//報錯
函數中的變量只會提前到函數的作用域中的最前面,不會出去
預解析會分段(多對的script標簽中函數重名,預解析的時候不會沖突)
function f1() {
console.log(num);//undefined
var num=10;
}
f1();
console.log(num);//
function f1() {
console.log("哈哈");
}
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
在前面項目的基礎上繼續,因為我們的項目進來頁面主題就是用戶數據,所以我們想讓它一進來就是高亮狀態,那么我們可以這樣做,同時我們再加上一個菜單:
<template> <div> <el-menu
style="width: 200px; min-height: calc(100vh - 50px)" default-active="user" :default-openeds="[1]" class="el-menu-vertical-demo"> <!--這是兩個函數,我們可以先不寫@open="handleOpen"--> <!--@close="handleClose"--> <el-sub-menu index="1"> <template #title>系統管理</template> <el-menu-item index="user" :route-="{path:'/'}">用戶管理</el-menu-item> </el-sub-menu> <el-menu-item index="data" :route-="{path:'/'}">數據管理</el-menu-item> </el-menu> </div> </template> <script> export default { name: "Aside" } </script> <style scoped> </style>
訪問效果如下:
可以看到一進來因為頁面主體是用戶管理界面,所以“用戶管理”菜單欄是默認高亮的,然后還多了一個數據管理的菜單欄。
菜單之間怎么跳轉一會兒再講,我們現在先寫注冊和登錄。
在寫注冊和登錄之前,我們先講一下路由,可以看到我們這個路由文件下的文件中,默認的“/”訪問的是Home文件:
Home頁面寫的就是我們這個用戶表的增刪改查,然后Home頁面呢是在我們的App.vue中給它嵌入進去了的,<router-view>就是展示的Home,還有Header啊Aside等
首先我們嘗試一下可不可以直接在路由文件下寫上一個Login路由,同時我們在views頁面下創建一個Login.vue,看看能不能成功:
注意引入路由的寫法要特別注意,不能直接像下面這樣寫:
而應該用引入的方式;
現在我們重啟訪問/login:
成功;
但是同時我們也看到了問題,我們明明是登錄界面,為什么進到了后臺主頁了,而我們想要的登錄界面應該是一個非常獨立的界面,所以我們的這個路由是有問題的。因為我們之前是直接使用App.vue作為項目的框架,其實這個App.vue在我們的main.js里面是引入進來了的:
引進來之后呢直接作為createApp的根節點來使用,所以這個App.vue這個界面呢,不適合用來作為我們的這個后臺骨架來使用:
它應該是一個全局的根節點,所以我們需要把App.vue里面的東西把它給挪走,挪到另一個界面,我們要把App.vue呢給它空出來,讓App.vue可以直接訪問我們所有的界面。
怎么做呢?
我們在src目錄下新建一個layout文件夾,這個文件夾呢就用來做我們項目的骨架部分,再在這個文件下建一個Layout組件:
然后把之前在App.vue的東西copy過來:
然后Header啊Aside啊那些組件我們需要在這個組件里面進行引入,然后App里面的那些原來引入的就刪掉就行了:
然后現在我們就完成了遷移,現在我們要去配置一下我們的路由,實現我們后臺的一個訪問。
路由怎么配置呢?非常簡單。
我們來講解一下剛才這個什么意思,App.vue里面我們只寫了一個router-view,而這個router-view呢就作為我們這個全局的一個根節點訪問,
這個router-view里面既可以是登錄界面也可以是注冊界面也可以是后臺主體,就是根據它是路由進行一個展示。當我們訪問到我們的后臺主體的時候,會進行一個二次的嵌套路由,那這個嵌套路由怎么寫呢?我們先配置登錄頁面的路由和后臺管理布局的路由:
此時訪問/和訪問/login都能到達對應的頁面:
但是訪問/時,Home主體頁面并沒有出來,只出來了/對應的頁面骨架的路由,怎么讓這個Home主體頁面出來呢,這就涉及到了嵌套路由,像下面這樣寫,children屬性是一個數組屬性,意味著其可以嵌套多個路由:
訪問/下的home路由,可以看到如下頁面:
vue-router給我們提供了重定向屬性,可以讓我們在訪問某個路由頁面時自動重定向到一個我們指定的路由頁面:
現在我們直接訪問/試試,可以看到依然是訪問的home頁面:
現在路由問題解決之后我們就可以去寫我們的登錄頁面了。
<template> <!--將整個瀏覽器頁面放在一個大div里
width: 100%表示這個讓div撐滿全屏
height: 100vh同上,一個撐滿高度一個撐滿寬度--> <div style="width: 100%; height: 100vh;background: darkslateblue; overflow: hidden"> <!--margin: 參數1 參數2; 參數1表示上下距離,參數2表示左右距離,auto表示自動匹配
如果頁面產生了空白,就在外層最大的div上加一個overflow,設置為hidden即可--> <div style="width: 400px; margin: 150px auto"> <!--font-size表示字體大小,text-align表示字體居中--> <div style="color: #cccccc; font-size: 30px; text-align: center; padding: 30px 0"> 歡迎登錄 </div> <!--然后去element上copy一個表單--> <el-form ref="form" :model="form" size="normal"> <el-form-item> <el-input prefix-icon="el-icon-user-solid" v-model="form.username"></el-input> </el-form-item> </el-form> <el-form ref="form" :model="form" size="normal"> <el-form-item> <el-input prefix-icon="el-icon-lock" v-model="form.password" show-password></el-input> </el-form-item> </el-form> <el-form ref="form" :model="form" size="normal"> <el-button style="width: 100%" type="primary" @click="login">登錄</el-button> </el-form> </div> </div> </template> <script> import request from "../utils/request"; export default { name: "Login", data(){ return{ form:{} } }, methods: { login() { request.post("/api/user/login",this.form).then(res => { if(res.code === "0"){ this.$messageBox({ type: "success", message: "登錄成功" }) // 登錄成功之后進行頁面跳轉,跳轉到主頁 this.$router.push("/") }else{ this.$messageBox({ type: "error", message: res.msg }) } }) } } } </script> <style scoped> </style>
然后現在去寫我們后端的接口:
//用戶登錄 @PostMapping("/login") public Result login(@RequestBody User user){ User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername()).eq(User::getPassword,user.getPassword())); if(res != null){ //登錄成功 return Result.success(); }else{ //登錄失敗 return Result.error("-1","用戶名或密碼錯誤"); } }
現在數據庫中的數據有:
我們試著訪問登錄:
可以看到登錄成功:
然后我們再去我們的網頁頭部右側的用戶信息欄寫一下退出系統的操作:
點擊則路由跳轉到登錄頁面。
然后還有注冊頁面,也一起寫了,注冊頁面其實邏輯和登錄界面差不多,我們copy一個登錄組件進行更改即可。
然后進行更改就行了,注冊不過就比登錄多了一個確認密碼的操作。
<template> <!--將整個瀏覽器頁面放在一個大div里
width: 100%表示這個讓div撐滿全屏
height: 100vh同上,一個撐滿高度一個撐滿寬度--> <div style="width: 100%; height: 100vh;background: darkslateblue; overflow: hidden"> <!--margin: 參數1 參數2; 參數1表示上下距離,參數2表示左右距離,auto表示自動匹配
如果頁面產生了空白,就在外層最大的div上加一個overflow,設置為hidden即可--> <div style="width: 400px; margin: 150px auto"> <!--font-size表示字體大小,text-align表示字體居中--> <div style="color: #cccccc; font-size: 30px; text-align: center; padding: 30px 0"> 歡迎登錄 </div> <!--然后去element上copy一個表單--> <el-form ref="form" :model="form" size="normal" :rules="rules"> <el-form-item prop="username"> <el-input prefix-icon="el-icon-user-solid" v-model="form.username"></el-input> </el-form-item> <el-form-item prop="password"> <el-input prefix-icon="el-icon-lock" v-model="form.password" show-password></el-input> </el-form-item> </el-form> <el-form ref="form" :model="form" size="normal"> <el-button style="width: 100%" type="primary" @click="login">登錄</el-button> </el-form> </div> </div> </template> <script> import request from "../utils/request"; export default { name: "Login", data(){ return{ form:{}, rules:{ username:[ {required: true,message:"請輸入用戶名",trigger:'blur'}, ], password:[ {required: true,message:"請輸入密碼",trigger:'blur'}, ] } } }, methods: { login() { //發送請求之前先加這個判斷,不為空且滿足規則時才發送請求 this.$refs['form'].validate((valid) => { if (valid) { request.post("/api/user/login",this.form).then(res => { if(res.code === "0"){ this.$messageBox({ type: "success", message: "登錄成功" }) // 登錄成功之后進行頁面跳轉,跳轉到主頁 this.$router.push("/") }else{ this.$messageBox({ type: "error", message: res.msg }) } }) } }) } } } </script> <style scoped> </style>
其中我們還要注意在請求數據之前要先判斷表單內部是否數據符合要求,否則不予請求,同樣在Login頁面內也要加入該判斷:
<template> <!--將整個瀏覽器頁面放在一個大div里
width: 100%表示這個讓div撐滿全屏
height: 100vh同上,一個撐滿高度一個撐滿寬度--> <div style="width: 100%; height: 100vh;background: darkslateblue; overflow: hidden"> <!--margin: 參數1 參數2; 參數1表示上下距離,參數2表示左右距離,auto表示自動匹配
如果頁面產生了空白,就在外層最大的div上加一個overflow,設置為hidden即可--> <div style="width: 400px; margin: 150px auto"> <!--font-size表示字體大小,text-align表示字體居中--> <div style="color: #cccccc; font-size: 30px; text-align: center; padding: 30px 0"> 歡迎登錄 </div> <!--然后去element上copy一個表單--> <el-form ref="form" :model="form" size="normal" :rules="rules"> <el-form-item prop="username"> <el-input prefix-icon="el-icon-user-solid" v-model="form.username"></el-input> </el-form-item> <el-form-item prop="password"> <el-input prefix-icon="el-icon-lock" v-model="form.password" show-password></el-input> </el-form-item> </el-form> <el-form ref="form" :model="form" size="normal"> <el-button style="width: 100%" type="primary" @click="login">登錄</el-button> </el-form> </div> </div> </template> <script> import request from "../utils/request"; export default { name: "Login", data(){ return{ form:{}, rules:{ username:[ {required: true,message:"請輸入用戶名",trigger:'blur'}, ], password:[ {required: true,message:"請輸入密碼",trigger:'blur'}, ] } } }, methods: { login() { //發送請求之前先加這個判斷,不為空且滿足規則時才發送請求 this.$refs['form'].validate((valid) => { if (valid) { request.post("/api/user/login",this.form).then(res => { if(res.code === "0"){ this.$messageBox({ type: "success", message: "登錄成功" }) // 登錄成功之后進行頁面跳轉,跳轉到主頁 this.$router.push("/") }else{ this.$messageBox({ type: "error", message: res.msg }) } }) } }) } } } </script> <style scoped> </style>
然后現在去后端寫register的接口:
//用戶注冊 @PostMapping("/register") public Result register(@RequestBody User user){ User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername())); if(res != null){ //說明用戶名重復 return Result.success(); } //該用戶不存在,予以注冊 if(user.getPassword() == null){ user.setPassword("123456"); } userMapper.insert(user); return Result.success(); }
就此我們的注冊頁面也寫完啦。
1
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
1.在搭建項目之前,先安裝淘寶鏡像和命令行工具,可能需要等待一段時間(電腦安裝過一遍之后,以后建項目時就不需要再安裝):
a.Win+R打開命令提示行cmd;
b.進入命令行cmd,設置淘寶鏡像;
npm config set registry https://registry.npm.taobao.org
c.安裝可生成腳手架代碼的命令行工具;
npm i -g @vue/cli
當命令行窗口顯示 [ + @vue/cli@版本號 ] 時說明安裝成功。
2.開始創建項目
a.先決定要把項目文件夾保存在哪個位置;此處以test文件夾為例;
b.進入test文件夾后,shift+鼠標右鍵打開power shell窗口;
c.運行 vue create 自定義項目名;此處以項目名為test為例,出現提示后按以下過程進行選擇:
1)? Please pick a preset:
2)? Check the features needed for your project:
3)? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) N
4)? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): (Use arrow keys)
5)? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
6)? Save this as a preset for future projects? (y/N) N
最后命令行窗口顯示Successfully created project xzvue說明項目創建成功。
此時我們便可在test文件夾中看到整個項目。
3.使用vscode打開并運行腳手架項目
(1)右鍵單擊package.json文件,選擇"在集成終端中打開";
(2)在終端窗口中輸入:npm run serve,等待后出現App running at : - Local :http://localhost:8080/,如下:
(3)按住Ctrl,點local:右側的連接,即可自動打開瀏覽器。
需要的時候就可以在集成終端中輸入npm i、npm i vant -S 等命令下載node_modules包、安裝vant等等。
注意vue采用的是熱編譯,修改后無需停止或重啟項目,只要一修改,就會立刻自動重新編譯,重新運行,自動在界面上顯示新內容。
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
提供的接口:http://localhost:7001/setUserList
2、新建:app / controller / new / user.js
1、初始化查詢列表數據:頁面展示列表,列表數據mouted獲取
2、頁面點擊新增:展示彈框,并將彈框內容去除掉,點擊新增,將彈框內容發送給后端
3、頁面點擊列表里面具體數據的編輯:彈框,并回填數據,修改將當前數據的id和表格數據傳給后端
4、刪除按鈕,點擊出現二次確認彈框,點擊確認將當前數據的id給后端就行
-
/**
-
* 路由配置
-
* @param app
-
*/
-
module.exports = app => {
-
const { router, controller } = app;
-
//--------------------------------------------------
-
// server接口
-
//--------------------------------------------------
-
app.get('/setUserList', controller.new.user.getUserList);
-
app.post('/setUserList', controller.new.user.postUserList);
-
app.put('/setUserList', controller.new.user.putUserList);
-
app.delete('/setUserList', controller.new.user.deleteUserList);
-
-
}
select * from user where name like ? % 內容 %
this.app.mysql.insert('表名',內容)
UPDATE loginlist SET `password` = 'Ad123456' WHERE id = 2
delete from user where id = 1
-
/**
-
* 用戶信息路由
-
* @param app
-
* @returns {HomeController}
-
*/
-
const Controller = require('egg').Controller;
-
class NewsController extends Controller {
-
async getUserList() {
-
//查詢庫里的user表
-
let params = this.ctx.query //獲取路徑后面的參數
-
console.log('用戶的參數:');
-
console.log(params);
-
let sql = 'select * from user'
-
let initSql = sql
-
-
let content = [];//參數
-
let isMore = false;//是否有多個查詢參數
-
/**
-
* @模糊查詢-量大的時候效率低
-
* select * from user where name like ? % 內容 %
-
* 在user表中全局查找name值 == 內容的
-
* % 內容 % 全局查找內容
-
* 內容 % 查找以 內容 開頭的數據
-
* */
-
if(params.name){
-
sql += " where name like ?";
-
content.push( "%"+params.name+"%" );
-
isMore = true;
-
}
-
if(params.age){
-
if(isMore){//true代表有多個參數
-
sql += "and age LIKE ?";//and是兩個條件都必須滿足,or是或的關系
-
}else{
-
sql += " WHERE age LIKE ?";
-
}
-
content.push( "%"+params.age+"%" )
-
isMore = true;
-
}
-
if(params.address){
-
if(isMore){//true代表有多個參數
-
sql += "and address LIKE ?";//and是兩個條件都必須滿足,or是或的關系
-
}else{
-
sql += " WHERE address LIKE ?";
-
}
-
content.push( "%"+params.address+"%" )
-
isMore = true;
-
}
-
if(params.phone){
-
if(isMore){//true代表有多個參數
-
sql += "and phone LIKE ?";//and是兩個條件都必須滿足,or是或的關系
-
}else{
-
sql += " WHERE phone LIKE ?";
-
}
-
content.push( "%"+params.phone+"%" )
-
}
-
-
//開啟分頁
-
if(params.page || params.pageSize){
-
let current = params.page;//當前頁碼
-
let pageSize = params.pageSize;//一頁展示多少條數據
-
sql += " limit ?,?";
-
content.push((current-1)*pageSize,parseInt(pageSize));
-
}
-
-
let allList = await this.app.mysql.query(initSql);
-
let userList= await this.app.mysql.query(
-
sql,content
-
);
-
this.ctx.body = {
-
code:200,
-
masg:'success',
-
data: {
-
list:userList,
-
total:allList.length
-
}
-
};
-
}
-
/**
-
* 新增用戶信息
-
* INSERT INTO loginlist (aaa,bbb,ccc) VALUES ('"'+111+'","'+222+'","'+333+'"')
-
* this.app.mysql.insert('表名',內容)
-
* this.app.mysql.insert('表名',{
-
* name:123,
-
* age:1,
-
* address:西安
-
* })
-
*/
-
//
-
async postUserList() {
-
console.log(this.ctx.request.body);
-
//新增數據-user表
-
let data = this.ctx.request.body
-
data.id = parseInt(Math.random()*100000)
-
let insertResult = await this.app.mysql.insert(
-
'user', data
-
);
-
this.ctx.body = {
-
code:200,
-
masg:'success',
-
data:insertResult
-
};
-
}
-
/**
-
* 修改用戶信息
-
* UPDATE loginlist SET `password` = 'Ad123456' WHERE id = 2(唯一值),修改一個
-
* UPDATE loginlist SET username = 'admins', `password` = 'Ad123456' WHERE id = 2,修改多個
-
*/
-
async putUserList(){
-
//新增數據-user表
-
let id = this.ctx.query.id //獲取路徑后面的參數
-
let data = this.ctx.request.body
-
let sql = 'update user set '
-
let isMore = false;//是否有多個查詢參數
-
if(!id){
-
this.ctx.body = {
-
code:200,
-
masg:'warning',
-
data:'id沒有傳'
-
};
-
return
-
}
-
//姓名
-
if(data.name){
-
sql += 'name = "'+data.name+'"'
-
isMore = true
-
}
-
//年齡
-
if(data.age){
-
if(isMore){
-
sql += ',age = "'+data.age+'"'
-
}else{
-
sql += 'age = "'+data.age+'"'
-
}
-
isMore = true
-
}
-
//地址
-
if(data.address){
-
if(isMore){
-
sql += ',address = "'+data.address+'"'
-
}else{
-
sql += 'address = "'+data.address+'"'
-
}
-
isMore = true
-
}
-
//手機號
-
if(data.phone){
-
if(isMore){
-
sql += ',phone = "'+data.phone+'"'
-
}else{
-
sql += 'phone = "'+data.phone+'"'
-
}
-
isMore = true
-
}
-
//郵箱地址
-
if(data.email){
-
if(isMore){
-
sql += ',email = "'+data.email+'"'
-
}else{
-
sql += 'email = "'+data.email+'"'
-
}
-
}
-
sql += ' where id = ' + id
-
-
let insertResult = await this.app.mysql.query(sql)
-
this.ctx.body = {
-
code:200,
-
masg:'success',
-
data:insertResult
-
};
-
}
-
/**
-
* 注銷用戶接口
-
* DELETE FROM loginlist WHERE username = 'superman'
-
*/
-
async deleteUserList(){
-
//查詢庫里的user表
-
let params = this.ctx.query //獲取路徑后面的參數
-
console.log('用戶的參數:');
-
console.log(params);
-
let sql = 'delete from user where id = '+ params.id
-
let res = await this.app.mysql.query(
-
sql
-
);
-
this.ctx.body = {
-
code:200,
-
masg:'success',
-
data:res
-
};
-
-
}
-
-
/**
-
* 模糊查詢封裝方法
-
* @params = auth
-
* */
-
async query( auth ) {
-
const TABLE_NAME = 'user';
-
const QUERY_STR = 'id, name, age, phone, address';
-
let sql = `select ${QUERY_STR} from ${TABLE_NAME} where authName like "%${auth.authName}%"`;
-
const row = await this.app.mysql.query(sql);
-
return row;
-
}
-
-
-
}
-
module.exports = NewsController;
-
-
<el-table
-
:data="tableInfo.list"
-
style="width: 100%">
-
<el-table-column
-
type="index"
-
label="序號"
-
align="center">
-
</el-table-column>
-
<el-table-column
-
prop="name"
-
label="姓名"
-
align="center">
-
</el-table-column>
-
<el-table-column
-
prop="age"
-
label="年齡"
-
align="center">
-
</el-table-column>
-
<el-table-column
-
prop="address"
-
label="地址">
-
</el-table-column>
-
<el-table-column
-
prop="phone"
-
label="手機號">
-
</el-table-column>
-
<el-table-column
-
prop="email"
-
label="郵箱">
-
</el-table-column>
-
<el-table-column
-
label="操作"
-
width="100">
-
<template slot-scope="scope">
-
<el-button type="text" size="small" @click="editFun(scope.row)">編輯</el-button>
-
<el-button type="text" size="small" @click="deleteFun(scope.row)">刪除</el-button>
-
</template>
-
</el-table-column>
-
</el-table>
-
mounted(){
-
this.initPage()
-
},
-
methods: {
-
/***
-
* 獲取列表數據
-
*/
-
initPage() {
-
let params = {
-
page: this.tableInfo.page, //當前頁
-
pageSize: this.tableInfo.pageSize //一頁展示多少條
-
}
-
this.$axios.get('http://localhost:7001/setUserList',{
-
params
-
}).then(res => {
-
this.tableInfo.list = res.data.data.list
-
this.tableInfo.total = res.data.data.total
-
}).catch(error => {
-
this.$message(error.data.message)
-
})
-
},
-
-
}
-
<template>
-
<div class="pro_body">
-
<el-button type='success' @click="addModal">新增</el-button>
-
<el-table
-
:data="tableInfo.list"
-
style="width: 100%">
-
<el-table-column
-
type="index"
-
label="序號"
-
align="center">
-
</el-table-column>
-
<el-table-column
-
prop="name"
-
label="姓名"
-
align="center">
-
</el-table-column>
-
<el-table-column
-
prop="age"
-
label="年齡"
-
align="center">
-
</el-table-column>
-
<el-table-column
-
prop="address"
-
label="地址">
-
</el-table-column>
-
<el-table-column
-
prop="phone"
-
label="手機號">
-
</el-table-column>
-
<el-table-column
-
prop="email"
-
label="郵箱">
-
</el-table-column>
-
<el-table-column
-
label="操作"
-
width="100">
-
<template slot-scope="scope">
-
<el-button type="text" size="small" @click="editFun(scope.row)">編輯</el-button>
-
<el-button type="text" size="small" @click="deleteFun(scope.row)">刪除</el-button>
-
</template>
-
</el-table-column>
-
</el-table>
-
<el-pagination
-
class="work_pagination"
-
background
-
:layout="'total,prev, pager, next,sizes'"
-
:total="tableInfo.total"
-
:hide-on-single-page="false"
-
:current-page="tableInfo.page"
-
:page-size="tableInfo.pageSize"
-
@current-change="pageChange"
-
@size-change="pageSizeChange"
-
>
-
</el-pagination>
-
-
-
<!--彈框部分-->
-
<el-dialog
-
custom-class="modalName"
-
:visible.sync="modal.show"
-
:width="modal.type === 'delete'? '470px' : '800px'">
-
<h3 v-if="modal.type === 'add'" slot="title">新增</h3>
-
<h3 v-if="modal.type === 'edit'" slot="title">修改</h3>
-
<h3 v-if="modal.type === 'delete'" slot="title">提示</h3>
-
<div v-if="modal.type !== 'delete'" class="editNameBody">
-
<el-form class="editNameFrom" :model="modalFrom" label-width="120px" label-position="right">
-
<el-form-item label="姓名:">
-
<el-input v-model="modalFrom.name"></el-input>
-
</el-form-item>
-
<el-form-item label="年紀:">
-
<el-input v-model="modalFrom.age"></el-input>
-
</el-form-item>
-
<el-form-item label="手機號:">
-
<el-input v-model="modalFrom.phone"></el-input>
-
</el-form-item>
-
<el-form-item label="郵箱:">
-
<el-input v-model="modalFrom.email"></el-input>
-
</el-form-item>
-
<el-form-item label="地址:">
-
<el-input v-model="modalFrom.address" type="textarea"></el-input>
-
</el-form-item>
-
</el-form>
-
</div>
-
<div v-if="modal.type === 'delete'">
-
<i class="el-icon-warning" style="margin-right:7px;color:#FFAA00;font-size: 16px;"></i>請確認是否刪除
-
</div>
-
<div slot="footer" class="dialog-footer">
-
<el-button @click="modal.show = false">取 消</el-button>
-
<el-button v-if="modal.type === 'add'" type="primary" @click="addUserList">新增</el-button>
-
<el-button v-if="modal.type === 'edit'" type="primary" @click="editUserList">修改</el-button>
-
<el-button v-if="modal.type === 'delete'" type="primary" @click="deleteUserList">確 認</el-button>
-
</div>
-
</el-dialog>
-
-
-
</div>
-
</template>
-
-
<script>
-
export default {
-
data() {
-
return {
-
tableInfo:{
-
columns:[
-
{
-
title: '序號',
-
type: 'index',
-
},{
-
title: '姓名',
-
prop: 'name',
-
align: 'center'
-
},
-
{
-
title: '年齡',
-
prop: 'age',
-
align: 'center'
-
},{
-
title: '地址',
-
prop: 'address',
-
align: 'center'
-
},{
-
title: '郵箱',
-
prop: 'email',
-
align: 'center'
-
},{
-
title: '手機號',
-
prop: 'phone',
-
align: 'center'
-
},
-
{//內容slot
-
slot: 'operateT'
-
}
-
],
-
list:[],
-
page:1,
-
pageSize:10,
-
total:0,
-
},
-
modal:{
-
show:false,
-
type:'add'
-
},
-
modalFrom:{
-
name:'',
-
age:'',
-
phone:'',
-
address:'',
-
email:''
-
}
-
};
-
},
-
mounted(){
-
this.initPage()
-
},
-
methods: {
-
/***
-
* 獲取列表數據
-
*/
-
initPage() {
-
let params = {
-
page: this.tableInfo.page, //當前頁
-
pageSize: this.tableInfo.pageSize //一頁展示多少條
-
}
-
this.$axios.get('http://localhost:7001/setUserList',{
-
params
-
}).then(res => {
-
this.tableInfo.list = res.data.data.list
-
this.tableInfo.total = res.data.data.total
-
}).catch(error => {
-
this.$message(error.data.message)
-
})
-
},
-
/**
-
* 當前頁發生改變
-
* */
-
pageChange(page) {
-
this.tableInfo.page = page
-
this.initPage() //刷新列表數據
-
},
-
/**
-
* 當前第幾頁發生改變
-
* */
-
pageSizeChange(pageSize) {
-
this.tableInfo.page = 1
-
this.tableInfo.pageSize = pageSize
-
this.initPage() //刷新列表數據
-
},
-
//新增彈框
-
addModal(){
-
this.modalFrom ={
-
name:'',
-
age:'',
-
phone:'',
-
address:'',
-
email:''
-
}
-
this.modal.show = true
-
this.modal.type = 'add'
-
},
-
//修改彈框
-
editFun(row){
-
this.modalFrom = row
-
this.modal.show = true
-
this.modal.type = 'edit'
-
},
-
//刪除彈框
-
deleteFun(row){
-
this.modalFrom = row
-
this.modal.show = true
-
this.modal.type = 'delete'
-
},
-
addUserList(){
-
this.$axios({
-
method:'post',
-
url:'http://localhost:7001/setUserList',
-
data:this.modalFrom
-
}).then(res => {
-
this.$message.success('新增成功')
-
this.initPage() //刷新數據
-
this.modal.show = false
-
})
-
},
-
editUserList(){
-
this.$axios({
-
method:'put',
-
url:'http://localhost:7001/setUserList',
-
params:{
-
id:this.modalFrom.id
-
},
-
data:this.modalFrom
-
}).then(res => {
-
this.$message.success('修改成功')
-
this.initPage() //刷新數據
-
this.modal.show = false
-
})
-
},
-
deleteUserList(){
-
this.$axios({
-
method:'delete',
-
url:'http://localhost:7001/setUserList',
-
params:{
-
id:this.modalFrom.id
-
}
-
}).then(res => {
-
this.$message.success('刪除成功')
-
this.initPage() //刷新數據
-
this.modal.show = false
-
})
-
}
-
}
-
-
}
-
</script>
-
-
<style lang='scss'>
-
.modalName{
-
h3{
-
padding:10px;
-
}
-
}
-
</style>
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
在我們了解JSONP 和 CORS 之前我們先明確一下:
實際上,cors和jsonp都是用于解決跨域問題,當兩個頁面的協議、域名、端口號中有一個不一致時就存在了跨域,一旦出現跨域,瀏覽器發送跨域請求后,請求回來的數據都會被瀏覽器所攔截,準備一張圖給大家看看:
現下實現跨域數據請求,最主要的兩種解決方案分別是 JSONP 和 CORS 。
JSONP
(???)
JSONP
(JSON with Padding
) 是 JSON
的一種“使用模式”,可用于解決主流瀏覽器的跨域數據訪問的問題。
JSONP
的實現原理(???)
概念:瀏覽器端通過 <script>
標簽的 src
屬性,請求服務器上的數據,同時,服務器返回一個函數的調用。這種請求數據的方式叫做 JSONP
特點:
JSONP
不屬于真正的 Ajax
請求,因為它沒有使用 XMLHttpRequest
這個對象
JSONP
僅支持 GET
請求,不支持 POST
、PUT
、DELETE
等請求
CORS
(跨域資源共享) 由一系列 HTTP
響應頭組成,這些 HTTP
響應頭決定瀏覽器 是否阻止前端 JS 代碼跨域獲取資源
瀏覽器的同源安全策略默認會阻止網頁“跨域”獲取資源。但如果接口服務器配置了 CORS 相關的 HTTP 響應頭,就可以解除瀏覽器端的跨域訪問限制
index.html文件代碼演示:
-
<!DOCTYPE html>
-
<html lang="en">
-
-
<head>
-
<meta charset="UTF-8">
-
<meta http-equiv="X-UA-Compatible" content="IE=edge">
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
-
<title>Document</title>
-
<script src="jquery.min.js"></script>
-
</head>
-
-
<body>
-
<button class="get">get請求</button>
-
<button class="post">post請求</button>
-
<script>
-
$('.get').on('click', function() {
-
$.ajax({
-
method: 'get',
-
url: 'http://127.0.0.1/api/get?name=hua&age=18',
-
success: function(res) {
-
console.log(res);
-
}
-
})
-
})
-
$('.post').on('click', function() {
-
$.ajax({
-
method: 'post',
-
url: 'http://127.0.0.1/api/post',
-
data: {
-
name: 'lajitong',
-
age: '111'
-
},
-
success: function(res) {
-
console.log(res);
-
}
-
})
-
})
-
</script>
-
</body>
-
-
</html>
此時會出現跨域問題,我們需要使用 cors 中間件解決跨域問題
cors 是 Express 的一個第三方中間件。通過安裝和配置 cors 中間件,可以很方便地解決跨域問題
使用步驟
安裝中間件: npm install cors
導入中間件: const cors = require('cors')
配置中間件: 在路由之前調用app.use(cors())
express接口案例代碼
-
// 導入 express 模塊
-
const express = require('express')
-
-
// 創建 express 的服務器實例
-
const app = express()
-
-
// 導入中間件
-
const cors = require('cors')
-
// 配置中間件
-
app.use(cors())
-
-
// 配置解析表單數據的中間件
-
app.use(express.urlencoded({ extended: false }))
-
-
// 導入路由模塊(被單獨分離后導入)
-
const router = require('./apiRouter')
-
// 把路由模塊,注冊到 app 上
-
app.use('/api', router)
-
-
// 調用 app.listen 方法,指定端口號并啟動 web 服務器
-
app.listen(80, () => {
-
console.log('http://127.0.0.1')
-
})
apiRouter路由文件代碼:
-
const express = require('express');
-
const router = express.Router();
-
-
router.get('/get', (req, res) => {
-
const query = req.query;
-
res.send({
-
status: 0,
-
msg: 'get請求成功',
-
data: query
-
})
-
})
-
router.post('/post', (req, res) => {
-
// const body = req.body; //獲取客戶端請求的數據
-
res.send({
-
status: 0,
-
msg: 'post請求成功',
-
data: req.body
-
})
-
})
-
module.exports = router;
在終端中運行express接口代碼后打開index.html文件并點擊get及post按鈕得到請求結果:
創建 JSONP
接口的注意事項
如果項目中已經配置了 CORS
跨域資源共享,為了防止沖突,必須在配置 CORS
中間件之前聲明 JSONP
的接口
否則 JSONP
接口會被處理成開啟了 CORS
的接口
實現步驟:
(1)獲取客戶端發送過來的回調函數的名字
(2)得到要通過 JSONP
形式發送給客戶端的數據
(3)根據前兩步得到的數據,拼接出一個函數調用的字符串
(4)把上一步拼接得到的字符串,響應給客戶端的 <script>
標簽進行解析執行
案例代碼如下:
-
//導入express模塊
-
const express = require('express');
-
//創建express服務器實例
-
const app = express();
-
//掛載路由
-
app.get('/jsonp', (req, res) => {
-
// 通過解構req.query客戶端通過查詢字符串的形式發送到客戶端的參數fn
-
const { callback } = req.query
-
//在服務器端定義一個obj對象
-
const obj = {
-
uname: 'zjj',
-
age: '18'
-
}
-
//obj對象轉為res.send可處理的字符串形式后從服務器端相應回調函數至客戶端
-
res.send(`${callback}(${JSON.stringify(obj)})`)
-
})
-
app.listen(80, () => {
-
console.log('http://127.0.0.1');
-
})
創建jsonp.html客戶端來接收服務器端響應過來的回調函數,代碼如下:
url中callback=fn為客戶端發送請求攜帶的參數 既服務器端中的req.query.callback
-
<script>
-
function fn(res) {
-
console.log(res);
-
}
-
</script>
-
<script src="http://127.0.0.1/jsonp?callback=fn"></script>
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
移動端瀏覽器兼容性較好,不需要考慮以前 JS 的兼容性問題,可以放心的使用原生 JS 書寫效果,但是移動端也有自己獨特的地方。比如觸屏事件 touch(也稱觸摸事件),Android 和 IOS 都有。
touch 對象代表一個觸摸點。觸摸點可能是一根手指,也可能是一根觸摸筆。觸屏事件可響應用戶手指(或觸控筆)對屏幕或者觸控板操作。
常見的觸屏事件:
觸摸事件對象(TouchEvent)
TouchEvent 是一類描述手指在觸摸平面(觸摸屏、觸摸板等)的狀態變化的事件。這類事件用于描述一個或多個觸點,使開發者可以檢測觸點的移動,觸點的增加和減少,等等
touchstart、touchmove、touchend 三個事件都會各自有事件對象。
觸摸事件對象常見對象列表:
因為平時都是給元素注冊觸摸事件,所以重點記住 targetTocuhes
移動端拖動元素JS代碼實現:
// (1) 觸摸元素 touchstart: 獲取手指初始坐標,同時獲得盒子原來的位置 // (2) 移動手指 touchmove: 計算手指的滑動距離,并且移動盒子 // (3) 離開手指 touchend: var div = document.querySelector('div'); var startX = 0; //獲取手指初始坐標 var startY = 0; var x = 0; //獲得盒子原來的位置 var y = 0; div.addEventListener('touchstart', function(e) { // 獲取手指初始坐標 startX = e.targetTouches[0].pageX; startY = e.targetTouches[0].pageY; x = this.offsetLeft; y = this.offsetTop; }); div.addEventListener('touchmove', function(e) { // 計算手指的移動距離: 手指移動之后的坐標減去手指初始的坐標 var moveX = e.targetTouches[0].pageX - startX; var moveY = e.targetTouches[0].pageY - startY; // 移動我們的盒子 盒子原來的位置 + 手指移動的距離 this.style.left = x + moveX + 'px'; this.style.top = y + moveY + 'px'; e.preventDefault(); // 阻止屏幕滾動的默認行為 });
classList屬性是HTML5新增的一個屬性。返回元素的類名,該屬性用在元素中添加、移除及切換CSS類
<style> .bg { background-color: black; } </style> <body> <div class="one two"></div> <button> 開關燈</button> <script> // classList 返回元素的類名 var div = document.querySelector('div'); // console.log(div.classList[1]); // 1. 添加類名 是在后面追加類名不會覆蓋以前的類名 注意前面不需要加. div.classList.add('three'); // 2. 刪除類名 div.classList.remove('one'); // 3. 切換類 var btn = document.querySelector('button'); btn.addEventListener('click', function() { document.body.classList.toggle('bg'); }) </script> </body>
移動端 要求的是快速開發,所以經常會借助于一些插件來幫完成操作
JS 插件是 js 文件,它遵循一定規范編寫,方便程序展示效果,擁有特定功能且方便調用。如輪播圖和瀑布流插件
插件的使用:
特點: 它一般是為了解決某個問題而專門存在,其功能單一,并且比較小。比如移動端常見插件:iScroll、Swiper、SuperSlider
offset 翻譯過來就是偏移量, 使用 offset 系列相關屬性可以 動態 的得到該元素的位置(偏移)、大小等。
常用屬性:
圖示:
offset與style區別:
offset | style |
---|---|
可以得到任意樣式表中的樣式值 | 只能得到行內樣式表中的樣式值 |
offset系列獲得的數值是沒有單位的 | style.width 獲得的是帶有單位的字符串 |
offsetWidth 包含padding+border+width | style.width 獲得不包含padding和border 的值 |
offsetWidth 等屬性是只讀屬性,只能獲取不能賦值 | style.width 是可讀寫屬性,可以獲取也可以賦值 |
獲取元素大小位置,用offset更合適 | 元素更改值,則需要用style改變 |
案例——獲取鼠標在盒子內的坐標:
效果展示:
實現代碼(JS):
// 在盒子內點擊, 想要得到鼠標距離盒子左右的距離。 // 首先得到鼠標在頁面中的坐標( e.pageX, e.pageY) // 其次得到盒子在頁面中的距離(box.offsetLeft, box.offsetTop) // 用鼠標距離頁面的坐標減去盒子在頁面中的距離, 得到 鼠標在盒子內的坐標 var box = document.querySelector('.box'); box.addEventListener('mousemove', function(e) { // console.log(e.pageX); // console.log(e.pageY); // console.log(box.offsetLeft); var x = e.pageX - this.offsetLeft; var y = e.pageY - this.offsetTop; this.innerHTML = 'x坐標是' + x + ' y坐標是' + y; })
案例——模態拖拽框:
效果展示:
實現代碼:
<head lang="en"> <meta charset="UTF-8"> <title></title> <style> .login-header { width: 100%; text-align: center; height: 30px; font-size: 24px; line-height: 30px; } ul,li,ol,dl,dt,dd,div,p,span,h1,h2,h3,h4,h5,h6,a { padding: 0px; margin: 0px; } .login { display: none; width: 512px; height: 280px; position: fixed; border: #ebebeb solid 1px; left: 50%; top: 50%; background: #ffffff; box-shadow: 0px 0px 20px #ddd; z-index: 9999; transform: translate(-50%, -50%); } .login-title { width: 100%; margin: 10px 0px 0px 0px; text-align: center; line-height: 40px; height: 40px; font-size: 18px; position: relative; cursor: move; } .login-input-content { margin-top: 20px; } .login-button { width: 50%; margin: 30px auto 0px auto; line-height: 40px; font-size: 14px; border: #ebebeb 1px solid; text-align: center; } .login-bg { display: none; width: 100%; height: 100%; position: fixed; top: 0px; left: 0px; background: rgba(0, 0, 0, .3); } a { text-decoration: none; color: #000000; } .login-button a { display: block; } .login-input input.list-input { float: left; line-height: 35px; height: 35px; width: 350px; border: #ebebeb 1px solid; text-indent: 5px; } .login-input { overflow: hidden; margin: 0px 0px 20px 0px; } .login-input label { float: left; width: 90px; padding-right: 10px; text-align: right; line-height: 35px; height: 35px; font-size: 14px; } .login-title span { position: absolute; font-size: 12px; right: -20px; top: -30px; background: #ffffff; border: #ebebeb solid 1px; width: 40px; height: 40px; border-radius: 20px; } </style> </head> <body> <div class="login-header"><a id="link" href="javascript:;">點擊,彈出登錄框</a></div> <div id="login" class="login"> <div id="title" class="login-title">登錄會員 <span><a id="closeBtn" href="javascript:void(0);" class="close-login">關閉</a></span> </div> <div class="login-input-content"> <div class="login-input"> <label>用戶名:</label> <input type="text" placeholder="請輸入用戶名" name="info[username]" id="username" class="list-input"> </div> <div class="login-input"> <label>登錄密碼:</label> <input type="password" placeholder="請輸入登錄密碼" name="info[password]" id="password" class="list-input"> </div> </div> <div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit">登錄會員</a></div> </div> <!-- 遮蓋層 --> <div id="bg" class="login-bg"></div> <script> // 1. 獲取元素 var login = document.querySelector('.login'); var mask = document.querySelector('.login-bg'); var link = document.querySelector('#link'); var closeBtn = document.querySelector('#closeBtn'); var title = document.querySelector('#title'); // 2. 點擊彈出層這個鏈接 link 讓mask 和login 顯示出來 link.addEventListener('click', function() { mask.style.display = 'block'; login.style.display = 'block'; }) // 3. 點擊 closeBtn 就隱藏 mask 和 login closeBtn.addEventListener('click', function() { mask.style.display = 'none'; login.style.display = 'none'; }) // 4. 開始拖拽 // (1) 當我們鼠標按下, 就獲得鼠標在盒子內的坐標 title.addEventListener('mousedown', function(e) { var x = e.pageX - login.offsetLeft; var y = e.pageY - login.offsetTop; // (2) 鼠標移動的時候,把鼠標在頁面中的坐標,減去 鼠標在盒子內的坐標就是模態框的left和top值 document.addEventListener('mousemove', move) function move(e) { login.style.left = e.pageX - x + 'px'; login.style.top = e.pageY - y + 'px'; } // (3) 鼠標彈起,就讓鼠標移動事件移除 document.addEventListener('mouseup', function() { document.removeEventListener('mousemove', move); }) }) </script> </body>
client 翻譯過來就是客戶端,使用 client 系列的相關屬性來獲取元素可視區的相關信息。通過 client 系列的相關屬性可以動態的得到該元素的邊框大小、元素大小等。
常用屬性:
client和offset最大的區別就是 :不包含邊框
圖示:
scroll 翻譯過來就是滾動的,使用 scroll 系列的相關屬性可以動態的得到該元素的大小、滾動距離等。
常用屬性:
圖示:
滾動條:
案例——固定右側側邊欄:
效果展示:
實現代碼:
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .slider-bar { position: absolute; left: 50%; top: 300px; margin-left: 600px; width: 45px; height: 130px; background-color: pink; } .w { width: 1200px; margin: 10px auto; } .header { height: 150px; background-color: purple; } .banner { height: 250px; background-color: skyblue; } .main { height: 1000px; background-color: yellowgreen; } span { display: none; position: absolute; bottom: 0; } </style> </head> <body> <div class="slider-bar"> <span class="goBack">返回頂部</span> </div> <div class="header w">頭部區域</div> <div class="banner w">banner區域</div> <div class="main w">主體部分</div> <script> //1. 獲取元素 var sliderbar = document.querySelector('.slider-bar'); var banner = document.querySelector('.banner'); // banner.offestTop 就是被卷去頭部的大小 一定要寫到滾動的外面 var bannerTop = banner.offsetTop // 當側邊欄固定定位之后應該變化的數值 var sliderbarTop = sliderbar.offsetTop - bannerTop; // 獲取main 主體元素 var main = document.querySelector('.main'); var goBack = document.querySelector('.goBack'); var mainTop = main.offsetTop; // 2. 頁面滾動事件 scroll document.addEventListener('scroll', function() { // window.pageYOffset 頁面被卷去的頭部 // console.log(window.pageYOffset); // 3 .當頁面被卷去的頭部大于等于了 172 此時 側邊欄就要改為固定定位 if (window.pageYOffset >= bannerTop) { sliderbar.style.position = 'fixed'; sliderbar.style.top = sliderbarTop + 'px'; } else { sliderbar.style.position = 'absolute'; sliderbar.style.top = '300px'; } // 4. 當我們頁面滾動到main盒子,就顯示 goback模塊 if (window.pageYOffset >= mainTop) { goBack.style.display = 'block'; } else { goBack.style.display = 'none'; } }) </script> </body>
三大系列作用區別:
它們主要用法:
系列 | 作用 | 屬性 |
---|---|---|
offset | 用于獲得元素位置 | offsetLeft offsetTop |
client | 用于獲取元素大小 | clientWidth clientHeight |
scroll | 用于獲取滾動距離 | scrollTop scrollLeft |
注意:頁面滾動的距離通過 window.pageXOffset 獲得
核心原理:通過定時器 setInterval() 不斷移動盒子位置
實現步驟:
簡單動畫函數封裝:
// 簡單動畫函數封裝obj目標對象 target 目標位置 function animate(obj, target) { var timer = setInterval(function() { if (obj.offsetLeft >= target) { // 停止動畫 本質是停止定時器 clearInterval(timer); } //每次均勻向右移動1px obj.style.left = obj.offsetLeft + 1 + 'px'; }, 30); }
緩動效果原理:
緩動動畫就是讓元素運動速度有所變化,最常見的是讓速度慢慢停下來
// 緩動動畫函數封裝obj目標對象 target 目標位置 // 思路: // 1. 讓盒子每次移動的距離慢慢變小, 速度就會慢慢落下來。 // 2. 核心算法:(目標值 - 現在的位置) / 10 做為每次移動的距離 步長 // 3. 停止的條件是: 讓當前盒子位置等于目標位置就停止定時器 function animate(obj, target) { // 先清除以前的定時器,只保留當前的一個定時器執行 clearInterval(obj.timer); obj.timer = setInterval(function() { // 步長值寫到定時器的里面 var step = (target - obj.offsetLeft) / 10; if (obj.offsetLeft == target) { // 停止動畫 本質是停止定時器 clearInterval(obj.timer); } // 把每次加1 這個步長值改為一個慢慢變小的值 步長公式:(目標值 - 現在的位置) / 10 obj.style.left = obj.offsetLeft + step + 'px'; }, 15); }
多個目標值之間移動:
當開始移動時候,判斷步長是正值還是負值
動畫函數封裝到單獨JS文件: animate.js
function animate(obj, target, callback) { // 先清除以前的定時器,只保留當前的一個定時器執行 clearInterval(obj.timer); obj.timer = setInterval(function() { // 步長值寫到定時器的里面 // 把步長值改為整數 不要出現小數的問題 // var step = Math.ceil((target - obj.offsetLeft) / 10); var step = (target - obj.offsetLeft) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if (obj.offsetLeft == target) { // 停止動畫 本質是停止定時器 clearInterval(obj.timer); // 回調函數寫到定時器結束里面 // if (callback) { // // 調用函數 // callback(); // } callback && callback(); } // 把每次加1 這個步長值改為一個慢慢變小的值 步長公式:(目標值 - 現在的位置) / 10 obj.style.left = obj.offsetLeft + step + 'px'; }, 15); }
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:csdn
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
首先我們為每個vue屬性用Object.defineProperty()實現數據劫持,為每個屬性分配一個訂閱者集合的管理數組dep;然后在編譯的時候在該屬性的數組dep中添加訂閱者,v-model會添加一個訂閱者,{{}}也會,v-bind也會,只要用到該屬性的指令理論上都會,接著為input會添加監聽事件,修改值就會為該屬性賦值,觸發該屬性的set方法,在set方法內通知訂閱者數組dep,訂閱者數組循環調用各訂閱者的update方法更新視圖。
一小段手寫實現代碼
僅供參考
1
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
Nodemailer 是一個基于Node的郵件服務模塊。
使用 Nodemailer 完成一個發郵件功能非常簡單,只需3步:
首先安裝 Nodemailer
npm install nodemailer
引入
var mailer = require('nodemailer');
創建 transport 使用 Nodemailer 的createTransport
方法,需要配置一下郵件服務。
首先,要在郵箱設置里開啟 SMTP 服務。
然后,設置一個客戶端授權密碼。
最后,寫一個配置文件(conf/mail.js
)。以126郵箱為例:
module.exports = { host: 'smtp.126.com', auth: { user: 'user@126.com', pass: '******' } }
host
字段配置剛才開啟的服務地址。
auth
里的user
字段配置郵箱賬號,pass
字段配置剛才設置的授權密碼。
這樣創建一個 transport:
var mailConf = require('conf/mail'); var transport = mailer.createTransport(mailConf);
發郵件使用 Nodemailer 的sendMail
方法,需要配置一下郵件內容。
這里配置了發件人,收件人,標題和正文:
var mailOptions = { from: mailConf.auth.user, to: 'receiver@xxx.com', subject: 'Hi, there', text: 'Mail from Node!' }
可以像官方文檔一樣定義一個回調函數:
function mailCallback(error, info){ if(error){ return console.log(error); } console.log('Message sent: ' + info.response); }
然后,就可以發送郵件了:
transport.sendMail(mailOptions, mailCallback);
這樣就完成了最基本的發郵件功能。
Nodemailer 文檔非常詳細,可以探索實現更多功能。
分享此文一切功德,皆悉回向給文章原作者及眾讀者.
轉自:簡書
免責聲明:藍藍設計尊重原作者,文章的版權歸原作者。如涉及版權問題,請及時與我們取得聯系,我們立即更正或刪除。
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
藍藍設計的小編 http://www.syprn.cn