2019高校微信小程序開發大賽獲獎作品——《brain頭腦智序》

目錄

前言

交互流程說明圖

我的任務

登錄授權(login)

首頁(tababr分析)

房間準備區(preparing)

便簽編輯區

最終方案選擇(房主權限)

會議報告頁面(report)


前言

今年4月份機緣巧合和團隊成員參加了2019 年高校微信小程序開發大賽,經過長時間的“頭腦風暴”,我們最終將主題定為“頭腦風暴”類——《brain頭腦智序》(喜歡的話到我們的github上star一下呀(*^▽^*))

我們開發這款項目的初衷是:

創造出一款針對“高效思維發散、打破思維定勢,優化思維產出”而設計的功能性實用且獨特,操作流程簡明扼要,界面簡潔而又新穎的小程序。

前期我們討論出來的項目必須要有的特點是:

  • 腦暴前:房主管理房間,成員們等待聽令
  • 腦暴時:匿名“發言”且多流程選擇
  • 腦暴后:會議結果報告生成圖及自定義導出保存

考慮到我們的項目是需要接近上線的,我們用到的后臺及數據庫就采用了基于微信自帶的云開發——看官方解釋:云開發為開發者提供完整的原生云端支持和微信服務支持,弱化后端和運維概念,無需搭建服務器,使用平臺提供的 API 進行核心業務開發,即可實現快速上線和迭代,同時這一能力,同開發者已經使用的云服務相互兼容,并不互斥。

簡而言之,就是無需購買自己的服務器、部署后端服務這些,云開發提供一站式后臺服務,直接在前臺利用api和云函數來操作各種后臺服務比如數據庫增刪改查以及文件存儲管理等(在新建項目的時候勾選創建 “云開發 QuickStart 項目”即可。當然空間大小也是有限制的,超了需要支付一定的金額),雖然速度上是慢了點,但是特容易上手,后臺小白如我也能操作,非常推薦!

關于云開發還需要提醒一下

  • 云開發需要指定環境,一般都是有一個測試環境,一個發布環境,開發的時候選擇測試環境即可。

  • Node.js云函數需要上傳并部署到云端才行,否則這些云函數都不起作用。


交互流程說明圖

先撒一張交互流程說明圖(這是前期設計的,后期開發的時候考慮到一些問題,我們并沒有嚴格按照此圖設計開發項目,會有一些小改動)

項目開發主要是我和另一個小伙伴一起操刀的

我的任務

我的任務主要是

  • 制作主頁、自定義中間凸起tabbar?
  • 利用微信云開發制作房間頁面,實時更新房間信息、房主邀請成員加入或踢出成員、準備狀態等
  • 會議報告頁面生成以及利用canvas導出自定義報告截圖并保存?

?而此次開發主要是要用到數據庫來存儲信息,數據庫預覽如下,分為集合和記錄,他們的關系是一對多的關系,即一個集合里包含有多條記錄,每條記錄都是擁有相同屬性的json對象。之后會專門說清楚如何操作數據庫。

?好的,接下來開始說明開發思路了


登錄授權(login)

我們的項目肯定是需要用戶的身份信息的,比如openid(用戶唯一標識)、頭像、昵稱等,所以需要一個登錄授權頁面才行

?云開發提供了login云函數可以方便快捷的獲取用戶的openid,那么在獲取用戶數據思路如下(注意:由于進入我們小程序的方式有兩條:1、正常點擊小程序進入首頁? ?2、點擊房主分享的鏈接直接進入房間等待區。所以我們需要在用戶進入小程序前捕獲他原本需要進入的頁面path)

  • 檢測用戶是否登錄過,有就直接進入path指定的url
  • 沒有的話則進入登錄授權頁面,登錄后將獲取到的數據分別保留到全局app.js和本地緩存中
  • 在后臺users集合中插入一條新用戶相關信息的記錄
  • 進入指定path

所以先在app.js的onLaunch函數中插入如下數據

    let userInfo = wx.getStorageSync('userInfo');let selfOpenId = wx.getStorageSync('selfOpenId');if (!selfOpenId || !userInfo.avatarUrl) {wx.reLaunch({url: 'pages/login/login?redirect_url=' + encodeURIComponent(`/${redirect_url}`),})return}

在登陸界面中,核心代碼如下:

    // 調用云函數wx.cloud.callFunction({name: 'login',data: {},success: res => {let openid = res.result.openid;//存儲用戶代碼app.globalData.selfOpenId = openid;wx.setStorageSync('userInfo', userInfo);//本地緩存用戶信息wx.setStorageSync('selfOpenId', openid);wx.hideLoading();that.setData({loading: false});//先查詢是否有此用戶記錄app.onQuery('users', { openid: openid }, { nickName: true }).then(res => {let data = res.data;if (data.length === 0) {//沒有則在users集合中新建一條記錄//多次會用到數據庫操作,建議直接封裝代碼到app.jsapp.onAdd('users', {//建立用戶的基本信息屬性avatarUrl: app.globalData.userInfo.avatarUrl,//頭像hisRoom: [],//用于歷史紀錄,查詢進去過的房間號nickName: app.globalData.userInfo.nickName,//昵稱star: [],userInfo: {},openid: app.globalData.selfOpenId}).then(()=>{console.log('插入用戶數據成功')})}else{console.log('用戶已有數據')}//開始跳轉頁面if (that.data.redirect_url) {console.log('跳轉開始')wx.redirectTo({url: that.data.redirect_url})} else {wx.redirectTo({//如果沒有指定redirect_url,默認跳轉到首頁url: 'pages/index/index'///!!!!})return }})  },fail: err => {console.error('[云函數] [login] 調用失敗', err)}})

?登陸完畢后,進入首頁啦


首頁(tababr分析)

首頁如下,簡潔吧嘻嘻(為了方便自己……一下參與者只有我……,但是實測過幾人參與也是能運行的!當然如果各位又遇到什么問題歡迎評論區狂砸我!)

首頁沒什么技術難點,主要還是tabbar如果需要中間有凸起效果的話是不能使用微信自帶的tabbar(小程序規定tabbar要老實點……)

所以我們需要自定義一個tabbar組件(其實我現在還沒實現組件化……時間問題,過段時間能透會氣的時候會優化一下這里)

在需要tababr的頁面注入這段代碼

<view class="tab-bar"><view wx:for="{{list}}" wx:key="index" class="tab-bar-item bar{{index}}" data-path="{{item.pagePath}}" data-index="{{index}}" bindtap="switchTab"><image wx:if="{{index!=1}}" class="image"  src="{{selected === index ? item.selectedIconPath : item.iconPath}}"></image><image wx:if="{{index==1}}" class="image  {{selected === index ? 'barson2':'barson1'}}"  src="{{selected === index ? item.selectedIconPath : item.iconPath}}"></image><view class="view" style="color: {{selected === index ? selectedColor : color}};">{{item.text}}</view></view>
</view>

js中list數據為:

//需要的數據  selected: 0,color: "#000000",//正常顏色selectedColor: "#4880ff",//高亮顏色list: [{iconPath: "../../icon/index.png",//正常圖標selectedIconPath: "../../icon/indexChecked.png",//高亮圖標text: "首頁"//文字顯示}, {iconPath: "../../icon/arrowbg.png",selectedIconPath: "../../icon/arrowbg.png",}, {iconPath: "../../icon/mine.png",selectedIconPath: "../../icon/mineChecked.png",text: "我的"}]//需要的函數switchTab: function (e) {const data = e.currentTarget.dataset  //獲取到DOM元素上的自定義屬性const url = data.path
//在for循環中,每個tab上的index屬性和它for循環的index掛鉤,這樣
//在點擊的時候就知道用戶點了哪個元素if (data.index === 1) { 
//點擊中間跳轉到創建房間頁面,由于創建頁面已經有一個退出房間的大叉叉圖標,
//所以不希望這里還能有返回頁面的按鈕,所以用redirectTowx.redirectTo({ url: '/pages/buildRooming/buildRooming' });this.setData({selected: 1  //selected與tabbar里for循環的index對應,如果兩者相同則證明該tab被點擊了
//需要高亮!})} else {this.setData({selected: data.index})}}

由于我們需要實現當用戶點擊某個tab的時候需要切換高亮的圖片和文字,那么我們一開始在js中利用list數組儲存tabbar需要的可以被遍歷使用的數據,包括:普通icon、高亮item和顯示文字。其次我們還需要的數據請看上面的代碼及上面的解釋。這里需要提示一下的是:

我將首頁頁面和我的頁面一起寫到一個wxml里,原因是tabbar他不是全局的,需要插入到每個需要他的頁面里,首頁和我的都需要tabbar,這樣一來有個問題,當點擊他們兩個tab相互切換頁面的時候tabbar會有加載延時,會閃一下,特別是網速慢的時候,可以很明顯的看出tabbar消失又出現了這樣一個問題。所以為了解決這個閃爍,況且這兩個頁面的內容也不多,不復雜1,就把他倆并在一起了。

至于中間的凸起圖標

思路是這樣的:

背景圖標用白色菱形圖片代替,注意設置樣式(在.bar1 .image里),普通和被點擊之間是通過類barson1與barson2來切換樣式的,這兩類的公共樣式都是利用偽元素::before和::after畫出兩條矩形然后讓其一旋轉90度,唯一不同的是點擊后圖標整體需要旋轉45度,以及顏色要變成紅色。當然給個過渡效果會更佳。


進入房間步驟,沒什么技術難度


?房間準備區(preparing)

這里需要考慮到的點有

  • 房間分兩個視角:普通成員——點擊準備按鈕切換準備狀態,此時該成員頭像也會變亮表示進入準備狀態;房主——房間第一位置且有專門的房主圖標表示,可以踢別人、在所有人都準備完畢才可以按開始討論按鈕并決定討論時長,點擊確認后所有人進入自己的編輯區點擊便簽開始寫下自己的想法,房主的步驟是不可逆的。
  • 房間實時性,所有的人都能實時、同步地獲取到房間的所有情況,包括誰進來了,誰被踢走了,誰在準備狀態了……
  • 最后一個位置始終都是分享按鈕
  • 如果成員過多要采用分頁狀態,設置左右滑動查看成員
  • 所有人可自行離開房間,如果房主選擇離開,那么按順位繼承房主名號(這里要注意如果只有房主一個人的情況下離開)
  • 如果房主已經處于設置討論時長的頁面,那么剩下的成員的準備按鈕要失效,不可再取消準備狀態
  • 如果新成員點擊分享鏈接加進來要先轉到登錄頁面,要儲存users的信息
  • 如果房間已經開始在討論階段了,如果又有人點擊分享鏈接加進來要給出相應提示,并返回主頁。

?創建的房間room集合的每條記錄所需屬性為:

  /* 插入數據 */app.onAdd('rooms',{title: inputValue.text,//房間討論主題roomNum: String(inputValue.roomNum),//房號roomMaster: { //房主信息openid: selfOpenId, avatarUrl: app.globalData.userInfo.avatarUrl, nickName: app.globalData.userInfo.nickName },readyArr: [],//準備好的成員openid,當長度===roomates.length-1時表示只有房主沒準備了roommates: [{ //保存房間所有人的信息openid:selfOpenId, avatarUrl: app.globalData.userInfo.avatarUrl, nickName: app.globalData.userInfo.nickName , ready: false }],allset: false,//對應readArr,當成員都準備好的時候,值為true,房主可以點擊開始討論按鈕inMeeting: false,//是否在討論中,如果是則其他人無法再進入房間preparingTime: 2,//房主設置的準備時長,用于閱讀腦暴規則meetingTime: 10,//討論時長again:false,//輪數是否為第二次開始,第一輪需要設置準備時長,二輪開始則不需要validPlan:[],//保存討論結束后的篩選出來的有效建議startTime:0,//記錄討論開始時間戳totalTime:'',//保存此次討論總時長date:'',//記錄討論日期hasRank:false,hasPersonal:false,reportAgain:false,goReport:false,goSelect:false})

分頁的話用swiper組件即可,

  data: {index: 0,join: 1,//點擊鏈接會傳入這個屬性,1表示是鏈接進來的,0表示房主allset: false,//表示房主已設置好時間,全部成員可以開始進入討論頁面了inputMsg: {//保存上一頁面傳來的房間信息roomNum: 0,text: '',},buttonText: '',//針對是房主還是成員切換按鈕文本dotsWidth: 0,//分頁指示點長度currentSwiper: 0,//分頁現在userInfo: [],//保存房間成員信息userInfoSwiper: [],//二維數組,里面的數組表示每8人信息組成一個arr,構成一頁,便于分頁顯示allTime: true//同步數據停止信號,如果為fasle則表示停止實時請求響應的請求},
<swiper current="{{currentSwiper}}" bindchange="swiperChange"><block wx:for="{{userInfoSwiper}}" wx:key="" wx:for-index="outerIndex" wx:for-item="outerItem">//每頁成員布局<swiper-item class='peopleList' bindtap='bindDelete'>//outerItem保存著內部arr,每個arr有8個或者8個一下的成員數據對象<block wx:for="{{outerItem}}" wx:key="" wx:for-index="innerIndex" wx:for-item="innerItem"><view class="peopleItem" id="{{innerIndex}}"><view class="imgPart" data-parentIndex="{{outerIndex}}" data-index="{{innerIndex}}"><image src='{{innerItem.avatarUrl}}' class="headImg" />//設置遮罩,房主不需要遮罩<view wx:if="{{!innerItem.ready && innerIndex != 0}}" class="map"></view>//設置房主圖標<view wx:if="{{ innerIndex ===0 && outerIndex === 0 }}" class="houseHolder" style="background:url('https://dmt-web-1257360276.cos.ap-guangzhou.myqcloud.com/%E5%A4%B4%E8%84%91%E6%99%BA%E5%BA%8F/roomowner.png') no-repeat ;background-size: 100%;"></view>//設置刪除圖標,不是房主則看不到此圖標<image wx:if="{{join===0}}" class="{{ outerIndex === 0 ? (innerIndex === 0 ? 'hidden' : 'delete' ): 'delete'}}" id="delete{{outerIndex*8+innerIndex}}" src="../../icon/delete.png" /></view><view class="nickName">{{innerItem.nickName}}</view></view></block>//結束循環//保留最后一頁的最后位置一定是分享按鈕<button wx:if="{{outerIndex===userInfoSwiper.length-1}}" class="invite" open-type='share' style="background:url('https://dmt-web-1257360276.cos.ap-guangzhou.myqcloud.com/%E5%A4%B4%E8%84%91%E6%99%BA%E5%BA%8F/join.png');background-size:100%"></button></swiper-item></block>
</swiper>

源代碼上都有注釋相信大家可以看得懂的,這里需要提一下如何做到同步數據,其實一開始我們是想要用websocket,它是一種建立在 TCP 協議之上的協議,它的最大特點就是,服務器可以主動向客戶端推送信息,客戶端也可以主動向服務器發送信息,是真正的雙向平等對話,屬于服務器推送技術的一種。現在的實時聊天技術都是可以基于這種協議來實現,但是由于我們還有學業上的作業要完成,留給我們項目的時間不多,而且我們是沒有怎么部署后端服務的,使用的是微信云開發提供的一站式后臺服務,不是自己的服務器操作起來確實有點麻煩,我們沒能及時實現它,后來就直接簡單粗暴的使用setTimeout函數模擬setInterval來不斷請求后臺數據庫信息來更新房間信息……

關于其他的呢,只要你把思路理清,需要哪些流程和步驟以及一些臨界條件,把需求一條條列出來(可看我上面列出的需要考慮的點)就可以輕松解決啦


便簽編輯區

開始討論(房主設置時長——所有人跳轉到閱讀討論規則——進入自定義編輯區,可利用便簽輸入自己的想法,可自定義便簽顏色):

選擇多輪討論(討論時間一到便跳轉到“意見”瀏覽區,所有成員的建議都集中在此,可點贊別人的建議(獲贊最多的成員獲“點贊王”稱號,可顯示在報告中)——隨后成員等待房主操作,如果房主選擇“再次討論”,則房主需要再次設置討論時長,所有人會再次進入便簽編輯區,此時可點擊“回顧排行榜”查看上一輪所有“建議”)

?

最終方案選擇(房主權限)

以下為房主視角,討論完畢房主進入選擇最終方案頁面,每輪點贊數由高到低排序,房主勾選出這幾輪中得出的最終方案,點擊確認按鈕后,所有成員集體跳轉到會議報告頁面

?

?


?會議報告頁面(report)

會議報告頁面:報告默認會顯示有效方案數、具體方案以及本次獲得贊最多的人,成員可以勾選所有排行榜上的每輪記錄或者自己發過的記錄實現自定義導出

?

導出報告頁面:導出后便可以自由查看自己想看的記錄

?

選擇“生成”按鈕會將會議報告生成圖片,保存到本地相冊,方便隨時查看

?好的我來具體說說會議報告頁面需要注意的點:

導出頁面的標題我限制了最多2行顯示,多余的用…顯示,核心代碼如下:

  let title = that.canvasWordBreak(300 * ratio, 16 * ratio, that.data.title);//限制在兩行以內顯示canvasWordBreak: function (maxWidth, fontSize, text) {//切割文字const maxNum = maxWidth / fontSize//每行最多顯示幾個字const textLength = text.length;//title字符串的長度let textRowArr = []let tmp = 0;let line = 2;//你需要顯示的最多行數while (line--) {textRowArr.push(text.substr(tmp, maxNum))tmp += maxNumif (tmp >= textLength) {//原文的字數以及小于每次累加的最大字數return textRowArr}if (line === 0) {//console.log(textRowArr[1][0],'line')let length = textRowArr[1].length;textRowArr[1] = textRowArr[1].substr(0, length - 1);//將最后一個字符變為...textRowArr[1] += '…';return textRowArr}}},

canvas繪圖因為需要具體的px數值,而我們的項目是需要動態導出需要的部分,有變化的部分包括標題的行數和排行榜或者個人記錄是否要導出。所以這里頁要注意不同屏幕尺寸大小,這里以iphone6尺寸為標準,設置比例 ratio =?windowWidth?/?375 即可

標題的話我先假設有2行,測試一行標題大概需要的高度差為?lineCha?=?22?*?Number(ratio),那么后續只需要判斷行數與高度差之間的關系即可,這里我算出的是

title.forEach((item, index) => {//由于主題可能會很長,拆分成幾個數組,一個數組一行顯示//if (index === 1) lineCha = 0;//由于一開始我是設置了2行文字顯示,所以下面的所有高度都是基于此的,//那么如果title是1行的話lineChaNum默認為1,即減去lineCha//如果是2行,則lineChaNum為0,2行以上則lineChaNum為1,即整體高度加lineCha,以此類推,本項目限制了最多只能2行顯示if (index >= 1) { lineChaNum = -1 * (index - 1) }context.setFontSize(16 * ratio);context.setFillStyle("#000000");context.fillText(item, 70 * ratio, height);height += 20 * ratio;
})

繪制圖片微信這邊的要求是要先將網絡路徑轉換成臨時路徑

//繪制canvas生成圖
//初始化圖片臨時路徑
that.getImgTempPath('https://dmt-web-1257360276.cos.ap-guangzhou.myqcloud.com/%E5%A4%B4%E8%84%91%E6%99%BA%E5%BA%8F/stared.png', 'star')
that.getImgTempPath('https://dmt-web-1257360276.cos.ap-guangzhou.myqcloud.com/%E5%A4%B4%E8%84%91%E6%99%BA%E5%BA%8F/circle.png', 'circle')that.getImgTempPath('https://dmt-web-1257360276.cos.ap-guangzhou.myqcloud.com/%E5%A4%B4%E8%84%91%E6%99%BA%E5%BA%8F/zanKing.png', 'kingCircle')//將網絡圖片轉成臨時路徑
getImgTempPath: function (url, data) {let that = this;wx.downloadFile({url: url, //success: function (res) {// 只要服務器有響應數據,就會把響應內容寫入文件并進入 success 回調,業務需要自行判斷是否下載到了想要的內容if (res.statusCode === 200) {//console.log(res.tempFilePath, "reererererer")that.setData({[data]: res.tempFilePath //動態生成屬性})}}})
},//將臨時路徑賦值給CanvasContext.drawImage()即可,具體參數還請移步微信官方文檔

至于排行榜和個人記錄,我分別用rankH和rankP變量來初始化他們的高度,由于是自定義選擇導出,可能會出現這些情況

  • if:如果有排行榜,那么需要先用rankH記錄它應該處于clientTop的距離,我這里是:rankH?=?450?*?ratio?-?lineCha?*?lineChaNum算式是可以不固定的,高度自行測試確定,看著舒服即可(就是這么隨便哈哈哈)再利用排行榜的數組數據遍歷循環繪制出每行數據,每行高度都要累加到rankH才能繪制出下一行,總之繪制的高度的表達式都要有rankH才行
  • else:如果沒有排行榜,則rankH就不需要累加了,我測試的時候rankH的值還需要再調整一下:rankH?=?380?*?ratio?-?lineCha?*?lineChaNum//如果不需要排行榜,則記錄此值為繪制下一部分的起始高度
  • if:如果有個人紀錄,那么他的起始高度為rankP?=?rankH?+?70?*?ratio;//承接排行榜的高度數值并調整成個人紀錄需要的高度,之后的累加是和排行榜一樣的套路了
  • else:如果沒有個人記錄,那么rankP?=?rankH,之后部分的繪制再依據rankP的數值調整即可。也就是說排行榜和個人紀錄都各自需要一個變量(rankH和rankP)來連接彼此(關系式),最后歸為一個變量(rankP)來處理,數值有什么變化,最后的變量也會相應更改,下面的部分的高度都依據rankP這個變量的改動而自我調節

具體還請看項目代碼,都有解釋的

最后展示生成的圖片

如果要想展示圖片,要先將canvas繪制到wxml里,然后再在js中利用canvas的canvasToTempFilePath接口繪制出圖片的臨時路徑

<!-- canvas繪圖區 -->
<view class='imagePathBox' hidden="{{maskHidden == false}}" id="imagePathBox" bindtap="hideCanvas"><image src="{{imagePath}}" class='shengcheng' mode="aspectFit" id="canvasImg"></image><view class="btnGroup"><button class='baocun' bindtap='saveImg'>保存</button><button class='cancel' bindtap='cancel'>取消</button></view>
</view>
<view hidden="{{maskHidden == false}}" class="mask"></view>
//先將canvas繪制于此,并隱藏起來
<view class="canvas-box"><canvas style="width: {{375*ratio}}px;height: {{canvasHeight*ratio}}px;position:fixed;top:99999px;" canvas-id="mycanvas" />
</view>
//把當前畫布指定區域的內容導出生成指定大小的圖片,需要延遲一會,繪制期間耗時
setTimeout(function () {wx.canvasToTempFilePath({canvasId: 'mycanvas',success: function (res) {var tempFilePath = res.tempFilePath;//生成文件的臨時路徑that.setData({imagePath: tempFilePath,//插入到image標簽的src可顯示canvasHidden: true});},fail: function (res) {console.log(res);}});
}, 300);

這里圖片高度其實大約就等于rankP的數值,因為方案那塊的繪制全部都是基于rankP累加的,因為繪制是基于左上角標準來繪制的,所以這里需要再加些數值,讓底部有些留白,我這里是:canvasHeight:?rankP?+?30?*?ratio

保存圖片的核心代碼為:

//點擊保存到相冊saveImg: function () {var that = thiswx.saveImageToPhotosAlbum({filePath: that.data.imagePath,//圖片的臨時路徑success(res) {wx.showModal({content: '圖片已保存到相冊!',showCancel: false,confirmText: '好的',confirmColor: '#333',success: function (res) {if (res.confirm) {console.log('用戶點擊確定');/* 該隱藏的隱藏 */that.setData({maskHidden: false})}}, fail: function (res) {console.log(11111)that.setData({maskHidden: false})}})}})},

至此!解說終于完畢啦,(擦擦汗……

說實話此次開發的時間比較短,很多代碼都急需優化才行,哭泣,找個寬裕的時間來開干!!

收獲還是蠻大的自己感覺,特別是開發一個要上線的項目,跟自己隨便搞搞的測試項目區別是超級大的,要努力加油呀!

好的不多說了,逃

如果有什么問題歡迎砸評論!ε=ε=ε=┏(゜ロ゜;)┛

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/251307.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/251307.shtml
英文地址,請注明出處:http://en.pswp.cn/news/251307.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

前端試題(三)

1. js繼承的7種方式 回顧&#xff1a; 每個構造函數都有一個原型對象&#xff1b;原型對象都包含一個指向構造函數的指針&#xff1b;實例都包含一個指向原型對象的內部指針&#xff1b;一切皆為對象&#xff0c;只要是對象&#xff0c;就會有 proto 屬性&#xff0c;該屬性存…

javascript --- ES6模塊與CommonJS模塊的差異

CommonJS模塊是運行時加載,ES6模塊是編譯時輸出接口 是因為CommonJS加載的是一個對象(module.exports屬性),該對象只有在腳本運行結束時才會生成.而ES6模塊不是對象,它的對外接口只是一種靜態定義,在代碼靜態解析階段就會生成. CommonJS模塊輸出的是一個值的復制&#xff0c;E…

C# ASP 面試題 2017

在博客上看到的&#xff0c;感覺還不錯 https://www.cnblogs.com/renyiqiu/p/6435261.html 轉載于:https://www.cnblogs.com/yangsirc/p/8038555.html

享元模式 - 結構型模式

模式類型&#xff1a; Flyweight 享元模式 - 結構型模式 意圖&#xff1a; The intent of this pattern is to use sharing to support a large number of objects that have part of their internal state in common where the other part of state can vary. 運用共享…

前端試題(四)

1. vue過濾器使用場景 2. v-on綁定多個方法 <p v-on"{click:dbClick,mousemove:MouseClick}"></p>一個事件綁定多個函數&#xff1a; <p click"one(),two()">點擊</p>3. 在菜單結構不確定時&#xff0c;前端如何動態渲染 樹形…

http --- 用于HTTP調試的最小型Perl Web 服務器

下面的程序是個很有用戶的診斷工具,可以用來調試與客戶端和代理的交互情況. 該程序 首先會等待HTTP連接,只有收到請求報文,就會將報文打印在屏幕上,然后等待用戶輸入一條響應報文,并將其回送給客戶端. #! /usr/bin/perl use Socket; use Carp; use FileHandle;# (1) use prot …

Mysql - 安裝與配置

1、下載安裝包 > https://www.mysql.com/downloads/ 2、雙擊安裝&#xff0c;點擊Install MySQL Products > 3、Skip 打鉤&#xff0c;Next下一步 > 4、選擇Server only&#xff1a;只選擇安裝服務端&#xff0c;根據個人喜好更改安裝路徑和數據保存路徑…

4084:拓撲排序

題目鏈接&#xff1a;http://bailian.openjudge.cn/practice/4084/ 總時間限制: 1000ms 內存限制: 65536kB描述給出一個圖的結構&#xff0c;輸出其拓撲排序序列&#xff0c;要求在同等條件下&#xff0c;編號小的頂點在前。 輸入若干行整數&#xff0c;第一行有2個數&#xff…

廖雪峰git教程學習

廖雪峰git教程 git – Linus在2周內用c寫的 1.1 基本概念 版本控制系統&#xff0c;追蹤文本文件的改動&#xff0c;文件、視頻等二進制文件則不可追蹤&#xff08;微軟的word也是二進制文件&#xff09;HEAD 指向當前分支&#xff0c;表示當前版本&#xff08;最新的提交&am…

操作系統 --- 進程和管程的不同

1.進程定義的是私有數據結構PCB,管程定義的是公共數據結構,如消息隊列等; 2.進程是由順序程序執行有關操作,而管程主要是進行同步操作和初始化操作; 3.設置進程的目的在于實現系統的并發行,而管程的設置則是解決共享資源的互斥使用問題; 4.進程通過調用管程中的過程對共享數據結…

JCO 自定義DestinationDataProvider

要讓JAVA程序能訪問SAP系統&#xff0c;一般通過SAP JCO接口進行通訊&#xff0c;在獲取到SAP的連接時需求提供一些連接參數&#xff0c;這些參數在最新的 JCO 3.0 中需要被保存到一個帶有擴展名.jcoDestination的文件中&#xff0c;這個文件同時被保存在應用程序的安裝目錄中。…

android BLE Peripheral 手機模擬設備發出BLE廣播 BluetoothLeAdvertiser

android 從4.3系統開始可以連接BLE設備&#xff0c;這個大家都知道了。iOS是從7.0版本開始支持BLE。android 進入5.0時代時&#xff0c;開放了一個新功能&#xff0c;手機可以模擬設備發出BLE廣播&#xff0c; 這個新功能其實是 對標于 iOS系統的手機模擬iBeacon設備。先介紹一…

前端后臺管理系統梳理

再梳理一遍 一、商品后臺管理系統 1. 功能 1.1 服務端情況 開啟了CORS跨域支持需要授權的 API &#xff0c;必須在請求頭中使用 Authorization 字段提供token 令牌&#xff08;axios攔截器&#xff09;baseUrl&#xff0c;接口地址&#xff1a;http://localhost:8888/api/…

操作系統 --- 使用套接字進行網絡通信

一個套接字就是一個通信標識類型的數據結構,包含了通信目的的地址、通信使用的端口號、通信網絡的傳輸協議、進程所在的網絡地址,以及針對客戶或服務器程序提供的不同系統調用等,是進程通信和網絡通信的基本構件。套接字是為客戶/服務器模型而設計的,通常分為以下兩類: 1.基于…

構造器執行順序

轉載于:https://www.cnblogs.com/a6948076/p/8045801.html

Java08-java語法基礎(七)構造方法

Java08-java語法基礎&#xff08;七&#xff09;構造方法 一、構造方法 1、什么是構造方法&#xff1f; 構造方法&#xff08;類方法&#xff09;是一個方法名和類名相容的特殊的成員方法。 2、構造方法的作用&#xff1f; 當使用new關鍵字創建一個對象時&#xff0c;為新建對象…

安裝mysql8.0.20,報錯“找不到VCRUNTIME140_1.dll”

寫在最前&#xff0c;指令集合 以管理員身份運行cmd mysql -uroot -p 【進入】mysql mysql > exit 【退出】 net stop mysql 【暫停】 net start mysql 【啟動】 mysql -u root -p&#xff08;命令后輸入臨時密碼&#xff0c;進入mysql&#xff09; ALTER USER USER() …

操作系統 --- 線程與進程的比較

如果說,在操作系統中引入進程的目的是為了使多個程序能并發執行,以提高資源利用率和系統吞吐量,那么在操作系統中再引入線程,則是為了減少程序在并發執行時所付出的時空開銷,使OS(操作系統)具有更好的并發性… 我們再回顧一下進程的兩個基本屬性: 1.進程是一個可擁擁有資源的獨…

24種吸引人的營銷文章標題寫法,總有一個適合你!

在如今信息爆炸的互聯網時代下&#xff0c;如何提高提高文章的閱讀(新聞稿、軟文宣傳稿、微信公眾號)&#xff0c;成為從業者們共同研究的課題?首先你得有一個足夠吸引的標題&#xff0c;尤其是定向推送的時候&#xff0c;這將是由一個質變帶來量變的過程。小編雖然不提倡標題…

[js] 處理字符串換行造成的json解析失敗

需求&#xff1a;從數據庫某個字段取出字符串出來&#xff0c;轉為json&#xff0c;結果發現報錯為 解析失敗&#xff0c;發現是因為取出的字符串換行導致&#xff0c;現在需要將字符串里面的換行替換為&#xff0c;使字符串可依成功解析成json對象。 技術&#xff1a;依靠repl…